From 8aaf5818a64e9f7687798852af5945b053c68a54 Mon Sep 17 00:00:00 2001 From: rdivacky Date: Tue, 4 May 2010 16:12:48 +0000 Subject: Update clang to r103004. --- lib/AST/APValue.cpp | 3 +- lib/AST/ASTContext.cpp | 211 +- lib/AST/ASTDiagnostic.cpp | 6 - lib/AST/ASTImporter.cpp | 28 +- lib/AST/Decl.cpp | 193 +- lib/AST/DeclBase.cpp | 38 +- lib/AST/DeclCXX.cpp | 48 +- lib/AST/DeclObjC.cpp | 18 +- lib/AST/DeclPrinter.cpp | 69 +- lib/AST/DeclTemplate.cpp | 22 +- lib/AST/DeclarationName.cpp | 59 +- lib/AST/Expr.cpp | 444 ++-- lib/AST/ExprCXX.cpp | 53 +- lib/AST/ExprConstant.cpp | 112 +- lib/AST/RecordLayoutBuilder.cpp | 568 +++-- lib/AST/RecordLayoutBuilder.h | 8 +- lib/AST/Stmt.cpp | 89 +- lib/AST/StmtDumper.cpp | 78 +- lib/AST/StmtPrinter.cpp | 73 +- lib/AST/StmtProfile.cpp | 28 + lib/AST/TemplateName.cpp | 18 +- lib/AST/Type.cpp | 20 +- lib/AST/TypePrinter.cpp | 4 +- lib/Analysis/CFG.cpp | 68 +- lib/Basic/Diagnostic.cpp | 70 +- lib/Basic/IdentifierTable.cpp | 6 +- lib/Basic/SourceManager.cpp | 100 +- lib/Basic/TargetInfo.cpp | 12 +- lib/Basic/Targets.cpp | 33 + lib/Checker/BasicObjCFoundationChecks.cpp | 41 +- lib/Checker/BasicStore.cpp | 2 +- lib/Checker/BugReporter.cpp | 2 +- lib/Checker/BugReporterVisitors.cpp | 14 +- lib/Checker/CFRefCount.cpp | 115 +- lib/Checker/CMakeLists.txt | 1 + lib/Checker/CallAndMessageChecker.cpp | 19 +- lib/Checker/CastToStructChecker.cpp | 2 +- lib/Checker/CheckObjCDealloc.cpp | 30 +- lib/Checker/CheckObjCInstMethSignature.cpp | 6 +- lib/Checker/CheckSecuritySyntaxOnly.cpp | 12 +- lib/Checker/Environment.cpp | 7 + lib/Checker/GRCXXExprEngine.cpp | 246 +++ lib/Checker/GRCoreEngine.cpp | 27 + lib/Checker/GRExprEngine.cpp | 369 +--- lib/Checker/MemRegion.cpp | 21 +- lib/Checker/NSAutoreleasePoolChecker.cpp | 2 +- lib/Checker/NSErrorChecker.cpp | 2 +- lib/Checker/ObjCUnusedIVarsChecker.cpp | 3 +- lib/Checker/RegionStore.cpp | 44 +- lib/Checker/SVals.cpp | 3 +- lib/Checker/SimpleSValuator.cpp | 22 +- lib/Checker/Store.cpp | 22 +- lib/Checker/UnixAPIChecker.cpp | 85 +- lib/CodeGen/CGBlocks.cpp | 24 +- lib/CodeGen/CGBlocks.h | 3 +- lib/CodeGen/CGBuiltin.cpp | 91 +- lib/CodeGen/CGCXX.cpp | 12 +- lib/CodeGen/CGCall.cpp | 11 +- lib/CodeGen/CGClass.cpp | 664 ++---- lib/CodeGen/CGDebugInfo.cpp | 209 +- lib/CodeGen/CGDebugInfo.h | 10 +- lib/CodeGen/CGDecl.cpp | 62 +- lib/CodeGen/CGDeclCXX.cpp | 11 +- lib/CodeGen/CGException.cpp | 235 ++- lib/CodeGen/CGExpr.cpp | 335 +-- lib/CodeGen/CGExprAgg.cpp | 25 +- lib/CodeGen/CGExprCXX.cpp | 50 +- lib/CodeGen/CGExprConstant.cpp | 579 ++--- lib/CodeGen/CGExprScalar.cpp | 133 +- lib/CodeGen/CGObjC.cpp | 216 +- lib/CodeGen/CGObjCGNU.cpp | 230 +- lib/CodeGen/CGObjCMac.cpp | 341 +-- lib/CodeGen/CGObjCRuntime.h | 5 +- lib/CodeGen/CGRTTI.cpp | 101 +- lib/CodeGen/CGRecordLayout.h | 134 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 306 ++- lib/CodeGen/CGStmt.cpp | 64 +- lib/CodeGen/CGTemporaries.cpp | 12 +- lib/CodeGen/CGVTT.cpp | 24 +- lib/CodeGen/CGVTables.cpp | 3167 +++++++++++++++++++++++++++ lib/CodeGen/CGVTables.h | 368 ++++ lib/CodeGen/CGValue.h | 67 +- lib/CodeGen/CGVtable.cpp | 3170 ---------------------------- lib/CodeGen/CGVtable.h | 361 ---- lib/CodeGen/CMakeLists.txt | 2 +- lib/CodeGen/CodeGenFunction.cpp | 24 +- lib/CodeGen/CodeGenFunction.h | 93 +- lib/CodeGen/CodeGenModule.cpp | 239 ++- lib/CodeGen/CodeGenModule.h | 37 +- lib/CodeGen/CodeGenTypes.h | 5 +- lib/CodeGen/Mangle.cpp | 239 ++- lib/CodeGen/Mangle.h | 12 +- lib/CodeGen/TargetInfo.cpp | 83 +- lib/Driver/Driver.cpp | 6 +- lib/Driver/ToolChains.cpp | 21 + lib/Driver/ToolChains.h | 17 +- lib/Driver/Tools.cpp | 129 +- lib/Driver/Tools.h | 5 + lib/Frontend/ASTConsumers.cpp | 191 +- lib/Frontend/ASTUnit.cpp | 18 +- lib/Frontend/AnalysisConsumer.cpp | 209 +- lib/Frontend/CacheTokens.cpp | 5 +- lib/Frontend/CodeGenAction.cpp | 313 +-- lib/Frontend/CompilerInstance.cpp | 19 +- lib/Frontend/CompilerInvocation.cpp | 135 +- lib/Frontend/FixItRewriter.cpp | 105 +- lib/Frontend/FrontendActions.cpp | 71 +- lib/Frontend/InitHeaderSearch.cpp | 59 +- lib/Frontend/InitPreprocessor.cpp | 30 +- lib/Frontend/LangStandards.cpp | 2 +- lib/Frontend/PCHReader.cpp | 34 +- lib/Frontend/PCHReaderDecl.cpp | 17 +- lib/Frontend/PCHReaderStmt.cpp | 135 +- lib/Frontend/PCHWriter.cpp | 15 +- lib/Frontend/PCHWriterDecl.cpp | 10 +- lib/Frontend/PCHWriterStmt.cpp | 83 +- lib/Frontend/PrintParserCallbacks.cpp | 9 +- lib/Frontend/PrintPreprocessedOutput.cpp | 50 +- lib/Frontend/RewriteMacros.cpp | 3 +- lib/Frontend/RewriteObjC.cpp | 528 ++--- lib/Frontend/StmtXML.cpp | 5 + lib/Frontend/TextDiagnosticPrinter.cpp | 24 +- lib/Frontend/VerifyDiagnosticsClient.cpp | 463 ++-- lib/Frontend/Warnings.cpp | 6 + lib/Headers/CMakeLists.txt | 2 + lib/Headers/altivec.h | 1483 +++++++++++++ lib/Headers/arm_neon.h | 537 +++++ lib/Headers/nmmintrin.h | 2 +- lib/Headers/stdint.h | 7 + lib/Headers/tmmintrin.h | 2 +- lib/Index/ASTLocation.cpp | 4 +- lib/Index/Analyzer.cpp | 79 +- lib/Lex/Lexer.cpp | 6 +- lib/Lex/LiteralSupport.cpp | 5 +- lib/Lex/PPDirectives.cpp | 24 +- lib/Lex/PPLexerChange.cpp | 20 +- lib/Lex/PPMacroExpansion.cpp | 31 +- lib/Lex/Preprocessor.cpp | 8 +- lib/Lex/TokenConcatenation.cpp | 6 +- lib/Parse/AttributeList.cpp | 3 +- lib/Parse/DeclSpec.cpp | 1 + lib/Parse/MinimalAction.cpp | 37 +- lib/Parse/ParseCXXInlineMethods.cpp | 50 +- lib/Parse/ParseDecl.cpp | 112 +- lib/Parse/ParseDeclCXX.cpp | 16 +- lib/Parse/ParseExpr.cpp | 106 +- lib/Parse/ParseExprCXX.cpp | 33 +- lib/Parse/ParseInit.cpp | 132 +- lib/Parse/ParseObjc.cpp | 350 ++- lib/Parse/ParseStmt.cpp | 13 +- lib/Parse/ParseTentative.cpp | 13 + lib/Parse/Parser.cpp | 12 +- lib/Rewrite/HTMLRewrite.cpp | 4 +- lib/Rewrite/Rewriter.cpp | 8 +- lib/Runtime/Makefile | 2 + lib/Sema/AnalysisBasedWarnings.cpp | 93 +- lib/Sema/AnalysisBasedWarnings.h | 4 +- lib/Sema/CodeCompleteConsumer.cpp | 4 +- lib/Sema/JumpDiagnostics.cpp | 4 +- lib/Sema/Lookup.h | 25 +- lib/Sema/ParseAST.cpp | 27 +- lib/Sema/Sema.cpp | 22 +- lib/Sema/Sema.h | 807 ++++--- lib/Sema/SemaAccess.cpp | 706 +++++-- lib/Sema/SemaCXXCast.cpp | 239 +-- lib/Sema/SemaCXXScopeSpec.cpp | 110 +- lib/Sema/SemaChecking.cpp | 198 +- lib/Sema/SemaCodeComplete.cpp | 584 ++++- lib/Sema/SemaDecl.cpp | 868 +++++--- lib/Sema/SemaDeclAttr.cpp | 58 +- lib/Sema/SemaDeclCXX.cpp | 2088 +++++++++--------- lib/Sema/SemaDeclObjC.cpp | 237 ++- lib/Sema/SemaExpr.cpp | 768 ++++--- lib/Sema/SemaExprCXX.cpp | 537 ++--- lib/Sema/SemaExprObjC.cpp | 1004 ++++++--- lib/Sema/SemaInit.cpp | 428 +++- lib/Sema/SemaInit.h | 60 +- lib/Sema/SemaLookup.cpp | 501 +++-- lib/Sema/SemaObjCProperty.cpp | 61 +- lib/Sema/SemaOverload.cpp | 798 +++++-- lib/Sema/SemaOverload.h | 35 +- lib/Sema/SemaStmt.cpp | 214 +- lib/Sema/SemaTemplate.cpp | 496 +++-- lib/Sema/SemaTemplateDeduction.cpp | 160 +- lib/Sema/SemaTemplateInstantiate.cpp | 274 ++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 336 +-- lib/Sema/SemaType.cpp | 124 +- lib/Sema/TreeTransform.h | 817 +++++-- 188 files changed, 21424 insertions(+), 12418 deletions(-) create mode 100644 lib/Checker/GRCXXExprEngine.cpp create mode 100644 lib/CodeGen/CGVTables.cpp create mode 100644 lib/CodeGen/CGVTables.h delete mode 100644 lib/CodeGen/CGVtable.cpp delete mode 100644 lib/CodeGen/CGVtable.h create mode 100644 lib/Headers/altivec.h create mode 100644 lib/Headers/arm_neon.h (limited to 'lib') diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 50a6e0a..731d5e0 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -48,7 +48,8 @@ const APValue &APValue::operator=(const APValue &RHS) { else if (isFloat()) setFloat(RHS.getFloat()); else if (isVector()) - setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength()); + setVector(((const Vec *)(const char *)RHS.Data)->Elts, + RHS.getVectorLength()); else if (isComplexInt()) setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); else if (isComplexFloat()) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c77acce..eea727d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -41,6 +41,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, Builtin::Context &builtins, bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + NSConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), @@ -325,55 +326,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } -CXXMethodVector::iterator CXXMethodVector::begin() const { - if ((Storage & 0x01) == 0) - return reinterpret_cast(&Storage); - - vector_type *Vec = reinterpret_cast(Storage & ~0x01); - return &Vec->front(); -} - -CXXMethodVector::iterator CXXMethodVector::end() const { - if ((Storage & 0x01) == 0) { - if (Storage == 0) - return reinterpret_cast(&Storage); - - return reinterpret_cast(&Storage) + 1; - } - - vector_type *Vec = reinterpret_cast(Storage & ~0x01); - return &Vec->front() + Vec->size(); -} - -void CXXMethodVector::push_back(const CXXMethodDecl *Method) { - if (Storage == 0) { - // 0 -> 1 element. - Storage = reinterpret_cast(Method); - return; - } - - vector_type *Vec; - if ((Storage & 0x01) == 0) { - // 1 -> 2 elements. Allocate a new vector and push the element into that - // vector. - Vec = new vector_type; - Vec->push_back(reinterpret_cast(Storage)); - Storage = reinterpret_cast(Vec) | 0x01; - } else - Vec = reinterpret_cast(Storage & ~0x01); - - // Add the new method to the vector. - Vec->push_back(Method); -} - -void CXXMethodVector::Destroy() { - if (Storage & 0x01) - delete reinterpret_cast(Storage & ~0x01); - - Storage = 0; -} - - ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap::const_iterator Pos @@ -515,7 +467,7 @@ ASTContext::getTypeInfo(const Type *T) { Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. - if (VT->getNumElements() & (VT->getNumElements()-1)) { + if (Align & (Align-1)) { Align = llvm::NextPowerOf2(Align); Width = llvm::RoundUpToAlignment(Width, Align); } @@ -701,10 +653,6 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast(T)->getNamedType().getTypePtr()); - case Type::InjectedClassName: - return getTypeInfo(cast(T) - ->getUnderlyingType().getTypePtr()); - case Type::TemplateSpecialization: assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); @@ -833,9 +781,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, CollectInheritedProtocols(SD, Protocols); SD = SD->getSuperClass(); } - return; - } - if (const ObjCCategoryDecl *OC = dyn_cast(CDecl)) { + } else if (const ObjCCategoryDecl *OC = dyn_cast(CDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); @@ -844,9 +790,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); } - return; - } - if (const ObjCProtocolDecl *OP = dyn_cast(CDecl)) { + } else if (const ObjCProtocolDecl *OP = dyn_cast(CDecl)) { for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), PE = OP->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); @@ -855,26 +799,20 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); } - return; } } unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) { unsigned count = 0; // Count ivars declared in class extension. - if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { - for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); I != E; ++I) { - ++count; - } - } - + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) + count += CDecl->ivar_size(); + // Count ivar defined in this class's implementation. This // includes synthesized ivars. if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) - for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), - E = ImplDecl->ivar_end(); I != E; ++I) - ++count; + count += ImplDecl->ivar_size(); + return count; } @@ -998,6 +936,11 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { ASTRecordLayoutBuilder::ComputeLayout(*this, D); ASTRecordLayouts[D] = NewEntry; + if (getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping AST Record Layout\n"; + DumpRecordLayout(D, llvm::errs()); + } + return *NewEntry; } @@ -1735,8 +1678,8 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa(Decl->TypeForDecl)); } else { - Decl->TypeForDecl = new (*this, TypeAlignment) - InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal()); + Decl->TypeForDecl = + new (*this, TypeAlignment) InjectedClassNameType(Decl, TST); Types.push_back(Decl->TypeForDecl); } return QualType(Decl->TypeForDecl, 0); @@ -1867,7 +1810,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { unsigned NumArgs = Args.size(); llvm::SmallVector ArgVec; @@ -1875,17 +1819,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, for (unsigned i = 0; i != NumArgs; ++i) ArgVec.push_back(Args[i].getArgument()); - return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon); + return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, + Canon, IsCurrentInstantiation); } QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { if (!Canon.isNull()) Canon = getCanonicalType(Canon); else { + assert(!IsCurrentInstantiation && + "current-instantiation specializations should always " + "have a canonical type"); + // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); llvm::SmallVector CanonArgs; @@ -1896,7 +1846,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, // Determine whether this canonical template specialization type already // exists. llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, + TemplateSpecializationType::Profile(ID, CanonTemplate, false, CanonArgs.data(), NumArgs, *this); void *InsertPos = 0; @@ -1908,7 +1858,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, void *Mem = Allocate((sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), TypeAlignment); - Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, + Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, false, CanonArgs.data(), NumArgs, Canon); Types.push_back(Spec); @@ -1928,7 +1878,9 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, sizeof(TemplateArgument) * NumArgs), TypeAlignment); TemplateSpecializationType *Spec - = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs, + = new (Mem) TemplateSpecializationType(*this, Template, + IsCurrentInstantiation, + Args, NumArgs, Canon); Types.push_back(Spec); @@ -2108,10 +2060,10 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, if (!InterfaceT.isCanonical() || !areSortedAndUniqued(Protocols, NumProtocols)) { if (!areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector Sorted(NumProtocols); + llvm::SmallVector Sorted(Protocols, + Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; - std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); SortAndUniqueProtocols(&Sorted[0], UniqueCount); Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), @@ -2154,8 +2106,8 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, // Sort the protocol list alphabetically to canonicalize it. QualType Canonical; if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector Sorted(NumProtocols); - std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); + llvm::SmallVector Sorted(Protocols, + Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; SortAndUniqueProtocols(&Sorted[0], UniqueCount); @@ -2634,14 +2586,9 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { QualType ASTContext::getBaseElementType(QualType QT) { QualifierCollector Qs; - while (true) { - const Type *UT = Qs.strip(QT); - if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) { - QT = AT->getElementType(); - } else { - return Qs.apply(QT); - } - } + while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0))) + QT = AT->getElementType(); + return Qs.apply(QT); } QualType ASTContext::getBaseElementType(const ArrayType *AT) { @@ -2886,6 +2833,7 @@ QualType ASTContext::getCFConstantStringType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } @@ -2901,6 +2849,46 @@ void ASTContext::setCFConstantStringType(QualType T) { CFConstantStringTypeDecl = Rec->getDecl(); } +// getNSConstantStringType - Return the type used for constant NSStrings. +QualType ASTContext::getNSConstantStringType() { + if (!NSConstantStringTypeDecl) { + NSConstantStringTypeDecl = + CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__builtin_NSString")); + NSConstantStringTypeDecl->startDefinition(); + + QualType FieldTypes[3]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.withConst()); + // const char *str; + FieldTypes[1] = getPointerType(CharTy.withConst()); + // unsigned int length; + FieldTypes[2] = UnsignedIntTy; + + // Create fields + for (unsigned i = 0; i < 3; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + Field->setAccess(AS_public); + NSConstantStringTypeDecl->addDecl(Field); + } + + NSConstantStringTypeDecl->completeDefinition(); + } + + return getTagDeclType(NSConstantStringTypeDecl); +} + +void ASTContext::setNSConstantStringType(QualType T) { + const RecordType *Rec = T->getAs(); + assert(Rec && "Invalid NSConstantStringType"); + NSConstantStringTypeDecl = Rec->getDecl(); +} + QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = @@ -2923,6 +2911,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } @@ -2960,6 +2949,7 @@ QualType ASTContext::getBlockDescriptorType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3008,6 +2998,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3085,6 +3076,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3129,6 +3121,7 @@ QualType ASTContext::getBlockParmType( &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3149,6 +3142,7 @@ QualType ASTContext::getBlockParmType( FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), Name, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3192,7 +3186,7 @@ std::string charUnitsToString(const CharUnits &CU) { return llvm::itostr(CU.getQuantity()); } -/// getObjCEncodingForBlockDecl - Return the encoded type for this method +/// getObjCEncodingForBlockDecl - Return the encoded type for this block /// declaration. void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S) { @@ -3207,7 +3201,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, SourceLocation Loc; CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); CharUnits ParmOffset = PtrSize; - for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); @@ -3258,7 +3252,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // their size. CharUnits ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), - E = Decl->param_end(); PI != E; ++PI) { + E = Decl->sel_param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); assert (sz.isPositive() && @@ -3272,7 +3266,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // Argument types. ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), - E = Decl->param_end(); PI != E; ++PI) { + E = Decl->sel_param_end(); PI != E; ++PI) { ParmVarDecl *PVDecl = *PI; QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = @@ -3494,13 +3488,18 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } + // encoding for pointer or r3eference types. + QualType PointeeTy; if (const PointerType *PT = T->getAs()) { if (PT->isObjCSelType()) { S += ':'; return; } - QualType PointeeTy = PT->getPointeeType(); - + PointeeTy = PT->getPointeeType(); + } + else if (const ReferenceType *RT = T->getAs()) + PointeeTy = RT->getPointeeType(); + if (!PointeeTy.isNull()) { bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of @@ -3524,12 +3523,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Another legacy compatibility encoding. Some ObjC qualifier and type // combinations need to be rearranged. // Rewrite "in const" from "nr" to "rn" - const char * s = S.c_str(); - int len = S.length(); - if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') { - std::string replace = "rn"; - S.replace(S.end()-2, S.end(), replace); - } + if (llvm::StringRef(S).endswith("nr")) + S.replace(S.end()-2, S.end(), "rn"); } if (PointeeTy->isCharType()) { @@ -3559,7 +3554,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, NULL); return; } - + if (const ArrayType *AT = // Ignore type qualifiers etc. dyn_cast(T->getCanonicalTypeInternal())) { @@ -4136,15 +4131,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT) { - if (RHSOPT->isObjCBuiltinType() || - LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType()) + if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) return true; if (LHSOPT->isObjCBuiltinType()) { return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); } - if (RHSOPT->isObjCQualifiedIdType()) + if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), QualType(RHSOPT,0), false); @@ -4190,7 +4184,8 @@ void getIntersectionOfProtocols(ASTContext &Context, unsigned RHSNumProtocols = RHS->getNumProtocols(); if (RHSNumProtocols > 0) { - ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin(); + ObjCProtocolDecl **RHSProtocols = + const_cast(RHS->qual_begin()); for (unsigned i = 0; i < RHSNumProtocols; ++i) if (InheritedProtocolSet.count(RHSProtocols[i])) IntersectionOfProtocols.push_back(RHSProtocols[i]); diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 866b7f7..e4cd2a9 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -57,12 +57,6 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, continue; } - // ...or an injected class name... - if (isa(Ty)) { - QT = cast(Ty)->desugar(); - continue; - } - // ...or a substituted template type parameter. if (isa(Ty)) { QT = cast(Ty)->desugar(); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 5dfb99f..ae09d79 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -612,8 +612,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const InjectedClassNameType *Inj1 = cast(T1); const InjectedClassNameType *Inj2 = cast(T2); if (!IsStructurallyEquivalent(Context, - Inj1->getUnderlyingType(), - Inj2->getUnderlyingType())) + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) return false; break; } @@ -1438,7 +1438,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { for (DeclContext::lookup_result Lookup = DC->lookup(Name); Lookup.first != Lookup.second; ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; if (NamespaceDecl *FoundNS = dyn_cast(*Lookup.first)) { @@ -1451,7 +1451,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { } if (!ConflictingDecls.empty()) { - Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(), ConflictingDecls.size()); } @@ -1905,6 +1905,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, Loc, Name, T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); } @@ -2125,7 +2126,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, - D->getStorageClass()); + D->getStorageClass(), + D->getStorageClassAsWritten()); // Import the qualifier, if any. if (D->getQualifier()) { NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); @@ -2197,6 +2199,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), /*FIXME: Default argument*/ 0); ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); return Importer.Imported(D, ToParm); @@ -2312,7 +2315,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ToMethod->addDecl(ToParams[I]); } ToMethod->setMethodParams(Importer.getToContext(), - ToParams.data(), ToParams.size()); + ToParams.data(), ToParams.size(), + ToParams.size()); ToMethod->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToMethod); @@ -2881,8 +2885,11 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { if (!SubExpr) return 0; + // FIXME: Initialize the base path. + assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); + CXXBaseSpecifierArray BasePath; return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(), - SubExpr, + SubExpr, BasePath, E->isLvalueCast()); } @@ -2899,8 +2906,11 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { if (!TInfo && E->getTypeInfoAsWritten()) return 0; + // FIXME: Initialize the base path. + assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); + CXXBaseSpecifierArray BasePath; return new (Importer.getToContext()) CStyleCastExpr(T, E->getCastKind(), - SubExpr, TInfo, + SubExpr, BasePath, TInfo, Importer.Import(E->getLParenLoc()), Importer.Import(E->getRParenLoc())); } @@ -3086,7 +3096,7 @@ FileID ASTImporter::Import(FileID FromID) { FromSLoc.getFile().getFileCharacteristic()); } else { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags()); + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM); llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dc9fb59..ffe4967 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -25,7 +25,6 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Parse/DeclSpec.h" #include "llvm/Support/ErrorHandling.h" -#include using namespace clang; @@ -286,6 +285,28 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { } Linkage NamedDecl::getLinkage() const { + + // Objective-C: treat all Objective-C declarations as having external + // linkage. + switch (getKind()) { + default: + break; + case Decl::ObjCAtDefsField: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCClass: + case Decl::ObjCCompatibleAlias: + case Decl::ObjCForwardProtocol: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCIvar: + case Decl::ObjCMethod: + case Decl::ObjCProperty: + case Decl::ObjCPropertyImpl: + case Decl::ObjCProtocol: + return ExternalLinkage; + } + // Handle linkage for namespace-scope names. if (getDeclContext()->getLookupContext()->isFileContext()) if (Linkage L = getLinkageForNamespaceScopeDecl(this)) @@ -354,88 +375,79 @@ std::string NamedDecl::getQualifiedNameAsString() const { } std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { - // FIXME: Collect contexts, then accumulate names to avoid unnecessary - // std::string thrashing. - std::vector Names; - std::string QualName; const DeclContext *Ctx = getDeclContext(); if (Ctx->isFunctionOrMethod()) return getNameAsString(); - while (Ctx) { + typedef llvm::SmallVector ContextsTy; + ContextsTy Contexts; + + // Collect contexts. + while (Ctx && isa(Ctx)) { + Contexts.push_back(Ctx); + Ctx = Ctx->getParent(); + }; + + std::string QualName; + llvm::raw_string_ostream OS(QualName); + + for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend(); + I != E; ++I) { if (const ClassTemplateSpecializationDecl *Spec - = dyn_cast(Ctx)) { + = dyn_cast(*I)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), P); - Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr); - } else if (const NamespaceDecl *ND = dyn_cast(Ctx)) { + OS << Spec->getName() << TemplateArgsStr; + } else if (const NamespaceDecl *ND = dyn_cast(*I)) { if (ND->isAnonymousNamespace()) - Names.push_back(""); + OS << ""; else - Names.push_back(ND->getNameAsString()); - } else if (const RecordDecl *RD = dyn_cast(Ctx)) { - if (!RD->getIdentifier()) { - std::string RecordString = "getKindName(); - RecordString += ">"; - Names.push_back(RecordString); - } else { - Names.push_back(RD->getNameAsString()); - } - } else if (const FunctionDecl *FD = dyn_cast(Ctx)) { - std::string Proto = FD->getNameAsString(); - + OS << ND; + } else if (const RecordDecl *RD = dyn_cast(*I)) { + if (!RD->getIdentifier()) + OS << "getKindName() << '>'; + else + OS << RD; + } else if (const FunctionDecl *FD = dyn_cast(*I)) { const FunctionProtoType *FT = 0; if (FD->hasWrittenPrototype()) FT = dyn_cast(FD->getType()->getAs()); - Proto += "("; + OS << FD << '('; if (FT) { - llvm::raw_string_ostream POut(Proto); unsigned NumParams = FD->getNumParams(); for (unsigned i = 0; i < NumParams; ++i) { if (i) - POut << ", "; + OS << ", "; std::string Param; FD->getParamDecl(i)->getType().getAsStringInternal(Param, P); - POut << Param; + OS << Param; } if (FT->isVariadic()) { if (NumParams > 0) - POut << ", "; - POut << "..."; + OS << ", "; + OS << "..."; } } - Proto += ")"; - - Names.push_back(Proto); - } else if (const NamedDecl *ND = dyn_cast(Ctx)) - Names.push_back(ND->getNameAsString()); - else - break; - - Ctx = Ctx->getParent(); + OS << ')'; + } else { + OS << cast(*I); + } + OS << "::"; } - std::vector::reverse_iterator - I = Names.rbegin(), - End = Names.rend(); - - for (; I!=End; ++I) - QualName += *I + "::"; - if (getDeclName()) - QualName += getNameAsString(); + OS << this; else - QualName += ""; + OS << ""; - return QualName; + return OS.str(); } bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { @@ -494,6 +506,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { } } +bool NamedDecl::isCXXInstanceMember() const { + assert(isCXXClassMember() && + "checking whether non-member is instance member"); + + const NamedDecl *D = this; + if (isa(D)) + D = cast(D)->getTargetDecl(); + + if (isa(D)) + return true; + if (isa(D)) + return cast(D)->isInstance(); + if (isa(D)) + return cast(cast(D) + ->getTemplatedDecl())->isInstance(); + return false; +} + //===----------------------------------------------------------------------===// // DeclaratorDecl Implementation //===----------------------------------------------------------------------===// @@ -568,8 +598,8 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S) { - return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S); + StorageClass S, StorageClass SCAsWritten) { + return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); } void VarDecl::Destroy(ASTContext& C) { @@ -793,8 +823,10 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); + StorageClass S, StorageClass SCAsWritten, + Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, + S, SCAsWritten, DefArg); } Expr *ParmVarDecl::getDefaultArg() { @@ -874,6 +906,12 @@ void FunctionDecl::getNameForDiagnostic(std::string &S, } +bool FunctionDecl::isVariadic() const { + if (const FunctionProtoType *FT = getType()->getAs()) + return FT->isVariadic(); + return false; +} + Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { if (I->Body) { @@ -1291,6 +1329,40 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, } } +void +FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs) { + assert(TemplateOrSpecialization.isNull()); + size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo); + Size += Templates.size() * sizeof(FunctionTemplateDecl*); + Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc); + void *Buffer = Context.Allocate(Size); + DependentFunctionTemplateSpecializationInfo *Info = + new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates, + TemplateArgs); + TemplateOrSpecialization = Info; +} + +DependentFunctionTemplateSpecializationInfo:: +DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, + const TemplateArgumentListInfo &TArgs) + : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { + + d.NumTemplates = Ts.size(); + d.NumArgs = TArgs.size(); + + FunctionTemplateDecl **TsArray = + const_cast(getTemplates()); + for (unsigned I = 0, E = Ts.size(); I != E; ++I) + TsArray[I] = cast(Ts[I]->getUnderlyingDecl()); + + TemplateArgumentLoc *ArgsArray = + const_cast(getTemplateArgs()); + for (unsigned I = 0, E = TArgs.size(); I != E; ++I) + new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); +} + TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. @@ -1407,6 +1479,10 @@ void TagDecl::startDefinition() { if (TagType *TagT = const_cast(TypeForDecl->getAs())) { TagT->decl.setPointer(this); TagT->decl.setInt(1); + } else if (InjectedClassNameType *Injected + = const_cast( + TypeForDecl->getAs())) { + Injected->Decl = cast(this); } if (isa(this)) { @@ -1428,6 +1504,11 @@ void TagDecl::completeDefinition() { assert(TagT->decl.getPointer() == this && "Attempt to redefine a tag definition?"); TagT->decl.setInt(0); + } else if (InjectedClassNameType *Injected + = const_cast( + TypeForDecl->getAs())) { + assert(Injected->Decl == this && + "Attempt to redefine a class template definition?"); } } @@ -1606,10 +1687,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass S, bool isInline, - bool hasWrittenPrototype) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); + StorageClass S, StorageClass SCAsWritten, + bool isInline, bool hasWrittenPrototype) { + FunctionDecl *New = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, + S, SCAsWritten, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index c693e15..b5aec0c 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -231,24 +231,28 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case CXXConstructor: case CXXDestructor: case CXXConversion: - case Typedef: case EnumConstant: case Var: case ImplicitParam: case ParmVar: case NonTypeTemplateParm: case ObjCMethod: - case ObjCContainer: - case ObjCInterface: case ObjCProperty: - case ObjCCompatibleAlias: return IDNS_Ordinary; + case ObjCCompatibleAlias: + case ObjCInterface: + return IDNS_Ordinary | IDNS_Type; + + case Typedef: + case UnresolvedUsingTypename: + case TemplateTypeParm: + return IDNS_Ordinary | IDNS_Type; + case UsingShadow: return 0; // we'll actually overwrite this later case UnresolvedUsingValue: - case UnresolvedUsingTypename: return IDNS_Ordinary | IDNS_Using; case Using: @@ -257,13 +261,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProtocol: return IDNS_ObjCProtocol; - case ObjCImplementation: - return IDNS_ObjCImplementation; - - case ObjCCategory: - case ObjCCategoryImpl: - return IDNS_ObjCCategoryName; - case Field: case ObjCAtDefsField: case ObjCIvar: @@ -272,16 +269,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Record: case CXXRecord: case Enum: - case TemplateTypeParm: - return IDNS_Tag; + return IDNS_Tag | IDNS_Type; case Namespace: - case Template: + case NamespaceAlias: + return IDNS_Namespace; + case FunctionTemplate: + return IDNS_Ordinary; + case ClassTemplate: case TemplateTemplateParm: - case NamespaceAlias: - return IDNS_Tag | IDNS_Ordinary; + return IDNS_Ordinary | IDNS_Tag | IDNS_Type; // Never have names. case Friend: @@ -295,10 +294,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Block: case TranslationUnit: - // Aren't looked up? case UsingDirective: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: + case ObjCImplementation: + case ObjCCategory: + case ObjCCategoryImpl: + // Never looked up by name. return 0; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 94ed85c..68f4a82 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -587,9 +587,9 @@ CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - bool isStatic, bool isInline) { + bool isStatic, StorageClass SCAsWritten, bool isInline) { return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo, - isStatic, isInline); + isStatic, SCAsWritten, isInline); } bool CXXMethodDecl::isUsualDeallocationFunction() const { @@ -633,6 +633,27 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { return true; } +bool CXXMethodDecl::isCopyAssignmentOperator() const { + // C++0x [class.copy]p19: + // A user-declared copy assignment operator X::operator= is a non-static + // non-template member function of class X with exactly one parameter of + // type X, X&, const X&, volatile X& or const volatile X&. + if (/*operator=*/getOverloadedOperator() != OO_Equal || + /*non-static*/ isStatic() || + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || + /*exactly one parameter*/getNumParams() != 1) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (const LValueReferenceType *Ref = ParamType->getAs()) + ParamType = Ref->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && @@ -659,15 +680,6 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { assert(isInstance() && "No 'this' for static methods!"); QualType ClassTy = C.getTypeDeclType(getParent()); - - // Aesthetically we prefer not to synthesize a type as the - // InjectedClassNameType of a template pattern: injected class names - // are printed without template arguments, which might - // surprise/confuse/distract our poor users if they didn't - // explicitly write one. - if (isa(ClassTy)) - ClassTy = cast(ClassTy)->getUnderlyingType(); - ClassTy = C.getQualifiedType(ClassTy, Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); @@ -686,9 +698,9 @@ bool CXXMethodDecl::hasInlineBody() const { CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, + TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, SourceLocation R) - : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual), LParenLoc(L), RParenLoc(R) { } @@ -745,11 +757,12 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isExplicit, - bool isInline, bool isImplicitlyDeclared) { + bool isInline, + bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline, - isImplicitlyDeclared); + return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, + isInline, isImplicitlyDeclared); } bool CXXConstructorDecl::isDefaultConstructor() const { @@ -848,8 +861,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, L, N, T, isInline, - isImplicitlyDeclared); + return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); } void diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 821e38b..dc4aacd 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -330,11 +330,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, bool isInstance, bool isVariadic, bool isSynthesized, - ImplementationControl impControl) { + ImplementationControl impControl, + unsigned numSelectorArgs) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, isInstance, - isVariadic, isSynthesized, impControl); + isVariadic, isSynthesized, impControl, + numSelectorArgs); } void ObjCMethodDecl::Destroy(ASTContext &C) { @@ -841,6 +843,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const { return 0; } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCCategoryImplDecl *CID) { + OS << CID->getName(); + return OS; +} + //===----------------------------------------------------------------------===// // ObjCImplementationDecl //===----------------------------------------------------------------------===// @@ -853,6 +861,12 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl); } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCImplementationDecl *ID) { + OS << ID->getName(); + return OS; +} + //===----------------------------------------------------------------------===// // ObjCCompatibleAliasDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index a625865..53949247 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -301,17 +301,15 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { - Out << "enum " << D->getNameAsString() << " {\n"; + Out << "enum " << D << " {\n"; VisitDeclContext(D); Indent() << "}"; } void DeclPrinter::VisitRecordDecl(RecordDecl *D) { Out << D->getKindName(); - if (D->getIdentifier()) { - Out << " "; - Out << D->getNameAsString(); - } + if (D->getIdentifier()) + Out << ' ' << D; if (D->isDefinition()) { Out << " {\n"; @@ -321,7 +319,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { } void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { - Out << D->getNameAsString(); + Out << D; if (Expr *Init = D->getInitExpr()) { Out << " = "; Init->printPretty(Out, Context, 0, Policy, Indentation); @@ -406,7 +404,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << ", "; if (BMInitializer->isMemberInitializer()) { FieldDecl *FD = BMInitializer->getMember(); - Out << FD->getNameAsString(); + Out << FD; } else { Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(); } @@ -537,7 +535,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { // C++ declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { - Out << "namespace " << D->getNameAsString() << " {\n"; + Out << "namespace " << D << " {\n"; VisitDeclContext(D); Indent() << "}"; } @@ -546,22 +544,20 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getNominatedNamespaceAsWritten()->getNameAsString(); + Out << D->getNominatedNamespaceAsWritten(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - Out << "namespace " << D->getNameAsString() << " = "; + Out << "namespace " << D << " = "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getAliasedNamespace()->getNameAsString(); + Out << D->getAliasedNamespace(); } void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << D->getKindName(); - if (D->getIdentifier()) { - Out << " "; - Out << D->getNameAsString(); - } + if (D->getIdentifier()) + Out << ' ' << D; if (D->isDefinition()) { // Print the base classes @@ -669,7 +665,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) { if (I != D->begin()) Out << ", "; - Out << I->getInterface()->getNameAsString(); + Out << I->getInterface(); } } @@ -688,8 +684,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { // FIXME: selector is missing here! pos = name.find_first_of(":", lastPos); Out << " " << name.substr(lastPos, pos - lastPos); - Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" - << (*PI)->getNameAsString(); + Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI; lastPos = pos + 1; } @@ -711,7 +706,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@implementation " << I << " : " << SID->getNameAsString(); + Out << "@implementation " << I << " : " << SID; else Out << "@implementation " << I; Out << "\n"; @@ -724,7 +719,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@interface " << I << " : " << SID->getNameAsString(); + Out << "@interface " << I << " : " << SID; else Out << "@interface " << I; @@ -733,7 +728,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { if (!Protocols.empty()) { for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); + Out << (I == Protocols.begin() ? '<' : ',') << *I; } if (!Protocols.empty()) @@ -744,8 +739,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << (*I)->getType().getAsString(Policy) - << ' ' << (*I)->getNameAsString() << ";\n"; + Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -762,20 +756,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { E = D->protocol_end(); I != E; ++I) { if (I != D->protocol_begin()) Out << ", "; - Out << (*I)->getNameAsString(); + Out << *I; } } void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - Out << "@protocol " << PID->getNameAsString() << '\n'; + Out << "@protocol " << PID << '\n'; VisitDeclContext(PID, false); Out << "@end"; } void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { - Out << "@implementation " - << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -783,9 +775,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " - << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -793,8 +783,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { } void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { - Out << "@compatibility_alias " << AID->getNameAsString() - << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; + Out << "@compatibility_alias " << AID + << ' ' << AID->getClassInterface() << ";\n"; } /// PrintObjCPropertyDecl - print a property declaration. @@ -854,8 +844,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { } Out << " )"; } - Out << ' ' << PDecl->getType().getAsString(Policy) - << ' ' << PDecl->getNameAsString(); + Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl; } void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { @@ -863,28 +852,28 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { Out << "@synthesize "; else Out << "@dynamic "; - Out << PID->getPropertyDecl()->getNameAsString(); + Out << PID->getPropertyDecl(); if (PID->getPropertyIvarDecl()) - Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); + Out << '=' << PID->getPropertyIvarDecl(); } void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; D->getTargetNestedNameDecl()->print(Out, Policy); - Out << D->getNameAsString(); + Out << D; } void DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { Out << "using typename "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getDeclName().getAsString(); + Out << D->getDeclName(); } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Out << "using "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getDeclName().getAsString(); + Out << D->getDeclName(); } void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index b449398..c498dea 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -178,6 +178,20 @@ void ClassTemplateDecl::Destroy(ASTContext& C) { C.Deallocate((void*)this); } +void ClassTemplateDecl::getPartialSpecializations( + llvm::SmallVectorImpl &PS) { + llvm::FoldingSet &PartialSpecs + = CommonPtr->PartialSpecializations; + PS.clear(); + PS.resize(PartialSpecs.size()); + for (llvm::FoldingSet::iterator + P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); + P != PEnd; ++P) { + assert(!PS[P->getSequenceNumber()]); + PS[P->getSequenceNumber()] = &*P; + } +} + ClassTemplatePartialSpecializationDecl * ClassTemplateDecl::findPartialSpecialization(QualType T) { ASTContext &Context = getASTContext(); @@ -186,7 +200,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { for (partial_spec_iterator P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (Context.hasSameType(Context.getTypeDeclType(&*P), T)) + if (Context.hasSameType(P->getInjectedSpecializationType(), T)) return &*P; } @@ -456,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateArgumentListBuilder &Builder, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl) { + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) { unsigned N = ArgInfos.size(); TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; for (unsigned I = 0; I != N; ++I) @@ -468,7 +483,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, SpecializedTemplate, Builder, ClonedArgs, N, - PrevDecl); + PrevDecl, + SequenceNumber); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getInjectedClassNameType(Result, CanonInjectedType); diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 19b58bc..4f85fca 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -18,7 +18,7 @@ #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include +#include "llvm/Support/raw_ostream.h" using namespace clang; namespace clang { @@ -202,32 +202,42 @@ bool DeclarationName::isDependentName() const { } std::string DeclarationName::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + printName(OS); + return OS.str(); +} + +void DeclarationName::printName(llvm::raw_ostream &OS) const { switch (getNameKind()) { case Identifier: if (const IdentifierInfo *II = getAsIdentifierInfo()) - return II->getName(); - return ""; + OS << II->getName(); + return; case ObjCZeroArgSelector: case ObjCOneArgSelector: case ObjCMultiArgSelector: - return getObjCSelector().getAsString(); + OS << getObjCSelector().getAsString(); + return; case CXXConstructorName: { QualType ClassType = getCXXNameType(); if (const RecordType *ClassRec = ClassType->getAs()) - return ClassRec->getDecl()->getNameAsString(); - return ClassType.getAsString(); + OS << ClassRec->getDecl(); + else + OS << ClassType.getAsString(); + return; } case CXXDestructorName: { - std::string Result = "~"; + OS << '~'; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs()) - Result += Rec->getDecl()->getNameAsString(); + OS << Rec->getDecl(); else - Result += Type.getAsString(); - return Result; + OS << Type.getAsString(); + return; } case CXXOperatorName: { @@ -240,32 +250,32 @@ std::string DeclarationName::getAsString() const { const char *OpName = OperatorNames[getCXXOverloadedOperator()]; assert(OpName && "not an overloaded operator"); - std::string Result = "operator"; + OS << "operator"; if (OpName[0] >= 'a' && OpName[0] <= 'z') - Result += ' '; - Result += OpName; - return Result; + OS << ' '; + OS << OpName; + return; } - case CXXLiteralOperatorName: { - return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName()); - } + case CXXLiteralOperatorName: + OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); + return; case CXXConversionFunctionName: { - std::string Result = "operator "; + OS << "operator "; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs()) - Result += Rec->getDecl()->getNameAsString(); + OS << Rec->getDecl(); else - Result += Type.getAsString(); - return Result; + OS << Type.getAsString(); + return; } case CXXUsingDirective: - return ""; + OS << ""; + return; } assert(false && "Unexpected declaration name kind"); - return ""; } QualType DeclarationName::getCXXNameType() const { @@ -369,7 +379,8 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - fprintf(stderr, "%s\n", getAsString().c_str()); + printName(llvm::errs()); + llvm::errs() << '\n'; } DeclarationNameTable::DeclarationNameTable() { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index ae4bc8c..00662a5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -27,6 +27,65 @@ #include using namespace clang; +/// isKnownToHaveBooleanValue - Return true if this is an integer expression +/// that is known to return 0 or 1. This happens for _Bool/bool expressions +/// but also int expressions which are produced by things like comparisons in +/// C. +bool Expr::isKnownToHaveBooleanValue() const { + // If this value has _Bool type, it is obvious 0/1. + if (getType()->isBooleanType()) return true; + // If this is a non-scalar-integer type, we don't care enough to try. + if (!getType()->isIntegralType()) return false; + + if (const ParenExpr *PE = dyn_cast(this)) + return PE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const UnaryOperator *UO = dyn_cast(this)) { + switch (UO->getOpcode()) { + case UnaryOperator::Plus: + case UnaryOperator::Extension: + return UO->getSubExpr()->isKnownToHaveBooleanValue(); + default: + return false; + } + } + + if (const CastExpr *CE = dyn_cast(this)) + return CE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const BinaryOperator *BO = dyn_cast(this)) { + switch (BO->getOpcode()) { + default: return false; + case BinaryOperator::LT: // Relational operators. + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: // Equality operators. + case BinaryOperator::NE: + case BinaryOperator::LAnd: // AND operator. + case BinaryOperator::LOr: // Logical OR operator. + return true; + + case BinaryOperator::And: // Bitwise AND operator. + case BinaryOperator::Xor: // Bitwise XOR operator. + case BinaryOperator::Or: // Bitwise OR operator. + // Handle things like (x==2)|(y==12). + return BO->getLHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->isKnownToHaveBooleanValue(); + + case BinaryOperator::Comma: + case BinaryOperator::Assign: + return BO->getRHS()->isKnownToHaveBooleanValue(); + } + } + + if (const ConditionalOperator *CO = dyn_cast(this)) + return CO->getTrueExpr()->isKnownToHaveBooleanValue() && + CO->getFalseExpr()->isKnownToHaveBooleanValue(); + + return false; +} + //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// @@ -231,14 +290,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { // For incorrect code, there might not be an ObjCInterfaceDecl. Do // a null check to avoid a crash. if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) - Out << ID->getNameAsString(); + Out << ID; if (const ObjCCategoryImplDecl *CID = - dyn_cast(MD->getDeclContext())) { - Out << '('; - Out << CID->getNameAsString(); - Out << ')'; - } + dyn_cast(MD->getDeclContext())) + Out << '(' << CID << ')'; + Out << ' '; Out << MD->getSelector().getAsString(); Out << ']'; @@ -492,17 +549,70 @@ QualType CallExpr::getCallReturnType() const { return FnType->getResultType(); } +OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, + SourceLocation OperatorLoc, + TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + + return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps, + exprsPtr, numExprs, RParenLoc); +} + +OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, + unsigned numComps, unsigned numExprs) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + return new (Mem) OffsetOfExpr(numComps, numExprs); +} + +OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) + : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false, + /*ValueDependent=*/tsi->getType()->isDependentType() || + hasAnyTypeDependentArguments(exprsPtr, numExprs) || + hasAnyValueDependentArguments(exprsPtr, numExprs)), + OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), + NumComps(numComps), NumExprs(numExprs) +{ + for(unsigned i = 0; i < numComps; ++i) { + setComponent(i, compsPtr[i]); + } + + for(unsigned i = 0; i < numExprs; ++i) { + setIndexExpr(i, exprsPtr[i]); + } +} + +IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { + assert(getKind() == Field || getKind() == Identifier); + if (getKind() == Field) + return getField()->getIdentifier(); + + return reinterpret_cast (Data & ~(uintptr_t)Mask); +} + MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, ValueDecl *memberdecl, - NamedDecl *founddecl, + DeclAccessPair founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); - bool hasQualOrFound = (qual != 0 || founddecl != memberdecl); + bool hasQualOrFound = (qual != 0 || + founddecl.getDecl() != memberdecl || + founddecl.getAccess() != memberdecl->getAccess()); if (hasQualOrFound) Size += sizeof(MemberNameQualifier); @@ -593,6 +703,12 @@ const char *CastExpr::getCastKindName() const { return 0; } +void CastExpr::DoDestroy(ASTContext &C) +{ + BasePath.Destroy(); + Expr::DoDestroy(C); +} + Expr *CastExpr::getSubExprAsWritten() { Expr *SubExpr = 0; CastExpr *E = this; @@ -720,10 +836,11 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(SourceLocation lbraceloc, +InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), false, false), + InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { @@ -734,24 +851,24 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc, ValueDependent = true; } - InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); + InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); } -void InitListExpr::reserveInits(unsigned NumInits) { +void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { if (NumInits > InitExprs.size()) - InitExprs.reserve(NumInits); + InitExprs.reserve(C, NumInits); } -void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) { +void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx) - InitExprs[Idx]->Destroy(Context); - InitExprs.resize(NumInits, 0); + InitExprs[Idx]->Destroy(C); + InitExprs.resize(C, NumInits, 0); } -Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { +Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { if (Init >= InitExprs.size()) { - InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0); + InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0); InitExprs.back() = expr; return 0; } @@ -835,19 +952,22 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, } case BinaryOperatorClass: { const BinaryOperator *BO = cast(this); - // Consider comma to have side effects if the LHS or RHS does. - if (BO->getOpcode() == BinaryOperator::Comma) { - // ((foo = ), 0) is an idiom for hiding the result (and - // lvalue-ness) of an assignment written in a macro. - if (IntegerLiteral *IE = - dyn_cast(BO->getRHS()->IgnoreParens())) - if (IE->getValue() == 0) - return false; - - return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || - BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + switch (BO->getOpcode()) { + default: + break; + // Consider ',', '||', '&&' to have side effects if the LHS or RHS does. + case BinaryOperator::Comma: + // ((foo = ), 0) is an idiom for hiding the result (and + // lvalue-ness) of an assignment written in a macro. + if (IntegerLiteral *IE = + dyn_cast(BO->getRHS()->IgnoreParens())) + if (IE->getValue() == 0) + return false; + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } - if (BO->isAssignmentOp()) return false; Loc = BO->getOperatorLoc(); @@ -1219,11 +1339,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case ObjCPropertyRefExprClass: // FIXME: check if read-only property. return LV_Valid; - case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property. + case ObjCImplicitSetterGetterRefExprClass: + // FIXME: check if read-only property. return LV_Valid; case PredefinedExprClass: return LV_Valid; case UnresolvedLookupExprClass: + case UnresolvedMemberExprClass: return LV_Valid; case CXXDefaultArgExprClass: return cast(this)->getExpr()->isLvalue(Ctx); @@ -1821,7 +1943,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case UnaryOperator::AddrOf: case UnaryOperator::Deref: return ICEDiag(2, E->getLocStart()); - case UnaryOperator::Extension: case UnaryOperator::LNot: case UnaryOperator::Plus: @@ -1831,6 +1952,12 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case UnaryOperator::Imag: return CheckICE(Exp->getSubExpr(), Ctx); case UnaryOperator::OffsetOf: + break; + } + + // OffsetOf falls through here. + } + case Expr::OffsetOfExprClass: { // Note that per C99, offsetof must be an ICE. And AFAIK, using // Evaluate matches the proposed gcc behavior for cases like // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect @@ -1838,7 +1965,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // array subscripts that aren't ICEs, and if the array subscripts // are ICEs, the value of the offsetof must be an integer constant. return CheckEvalInICE(E, Ctx); - } } case Expr::SizeOfAlignOfExprClass: { const SizeOfAlignOfExpr *Exp = cast(E); @@ -1936,7 +2062,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::ImplicitCastExprClass: case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: - case Expr::CXXNamedCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: { @@ -1953,7 +2078,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // then only the true side is actually considered in an integer constant // expression, and it is fully evaluated. This is an important GNU // extension. See GCC PR38377 for discussion. - if (const CallExpr *CallCE = dyn_cast(Exp->getCond()->IgnoreParenCasts())) + if (const CallExpr *CallCE + = dyn_cast(Exp->getCond()->IgnoreParenCasts())) if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { Expr::EvalResult EVResult; if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || @@ -2176,101 +2302,156 @@ void ExtVectorElementExpr::getEncodedElementAccess( } } -// constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver, - Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), - MethodProto(mproto) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = receiver; - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - -// constructor for class messages. -// FIXME: clsName should be typed to ObjCInterfaceType -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), - SelName(selInfo), MethodProto(mproto) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - -// constructor for class messages. -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, - ObjCMethodDecl *mproto, SourceLocation LBrac, - SourceLocation RBrac, Expr **ArgExprs, - unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), - SelName(selInfo), MethodProto(mproto) +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false, + /*ValueDependent=*/false), + NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), + HasMethod(Method != 0), SuperLoc(SuperLoc), + SelectorOrMethod(reinterpret_cast(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} + setReceiverPointer(SuperType.getAsOpaquePtr()); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, T->isDependentType(), + (T->isDependentType() || + hasAnyValueDependentArguments(Args, NumArgs))), + NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(), + (Receiver->isTypeDependent() || + hasAnyValueDependentArguments(Args, NumArgs))), + NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper, + SuperType, Sel, Method, Args, NumArgs, + RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, + NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, + NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, + unsigned NumArgs) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); +} + +Selector ObjCMessageExpr::getSelector() const { + if (HasMethod) + return reinterpret_cast(SelectorOrMethod) + ->getSelector(); + return Selector(SelectorOrMethod); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + switch (getReceiverKind()) { + case Instance: + if (const ObjCObjectPointerType *Ptr + = getInstanceReceiver()->getType()->getAs()) + return Ptr->getInterfaceDecl(); + break; -ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { - uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; - switch (x & Flags) { - default: - assert(false && "Invalid ObjCMessageExpr."); - case IsInstMeth: - return ClassInfo(0, 0, SourceLocation()); - case IsClsMethDeclUnknown: - return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc); - case IsClsMethDeclKnown: { - ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); - return ClassInfo(D, D->getIdentifier(), ClassNameLoc); - } - } -} + case Class: + if (const ObjCInterfaceType *Iface + = getClassReceiver()->getAs()) + return Iface->getDecl(); + break; -void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { - if (CI.Decl == 0 && CI.Name == 0) { - SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth); - return; - } + case SuperInstance: + if (const ObjCObjectPointerType *Ptr + = getSuperType()->getAs()) + return Ptr->getInterfaceDecl(); + break; - if (CI.Decl == 0) - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown); - else - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown); - ClassNameLoc = CI.Loc; -} + case SuperClass: + if (const ObjCObjectPointerType *Iface + = getSuperType()->getAs()) + return Iface->getInterfaceDecl(); + break; + } -void ObjCMessageExpr::DoDestroy(ASTContext &C) { - DestroyChildren(C); - if (SubExprs) - C.Deallocate(SubExprs); - this->~ObjCMessageExpr(); - C.Deallocate((void*) this); + return 0; } bool ChooseExpr::isConditionTrue(ASTContext &C) const { @@ -2577,6 +2758,15 @@ Stmt::child_iterator ParenExpr::child_end() { return &Val+1; } Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } +// OffsetOfExpr +Stmt::child_iterator OffsetOfExpr::child_begin() { + return reinterpret_cast (reinterpret_cast (this + 1) + + NumComps); +} +Stmt::child_iterator OffsetOfExpr::child_end() { + return child_iterator(&*child_begin() + NumExprs); +} + // SizeOfAlignOfExpr Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { // If this is of a type and the type is a VLA type (and not a typedef), the @@ -2746,10 +2936,12 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() { // ObjCMessageExpr Stmt::child_iterator ObjCMessageExpr::child_begin() { - return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; + if (getReceiverKind() == Instance) + return reinterpret_cast(this + 1); + return getArgs(); } Stmt::child_iterator ObjCMessageExpr::child_end() { - return &SubExprs[0]+ARGS_START+getNumArgs(); + return getArgs() + getNumArgs(); } // Blocks diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index b9a4ee6..2e03beb 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -18,16 +18,25 @@ #include "clang/AST/TypeLoc.h" using namespace clang; + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// +QualType CXXTypeidExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return Operand.get()->getType().getNonReferenceType() + .getUnqualifiedType(); +} + // CXXTypeidExpr - has child iterators if the operand is an expression Stmt::child_iterator CXXTypeidExpr::child_begin() { - return isTypeOperand() ? child_iterator() : &Operand.Ex; + return isTypeOperand() ? child_iterator() + : reinterpret_cast(&Operand); } Stmt::child_iterator CXXTypeidExpr::child_end() { - return isTypeOperand() ? child_iterator() : &Operand.Ex+1; + return isTypeOperand() ? child_iterator() + : reinterpret_cast(&Operand) + 1; } // CXXBoolLiteralExpr @@ -180,6 +189,13 @@ bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin, return false; } +CXXRecordDecl *OverloadExpr::getNamingClass() const { + if (isa(this)) + return cast(this)->getNamingClass(); + else + return cast(this)->getNamingClass(); +} + Stmt::child_iterator UnresolvedLookupExpr::child_begin() { return child_iterator(); } @@ -443,9 +459,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, SourceLocation tyBeginLoc, Expr **Args, unsigned NumArgs, - SourceLocation rParenLoc) + SourceLocation rParenLoc, + bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc, - Cons, false, Args, NumArgs), + Cons, false, Args, NumArgs, ZeroInitialization), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { } @@ -454,25 +471,25 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool ZeroInitialization, - bool BaseInitialization) { + ConstructionKind ConstructKind) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, NumArgs, ZeroInitialization, - BaseInitialization); + ConstructKind); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization, - bool BaseInitialization) + bool ZeroInitialization, + ConstructionKind ConstructKind) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), - BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs) + ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), + Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; @@ -712,15 +729,15 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { // If there was a nested name specifier, it names the naming class. // It can't be dependent: after all, we were actually able to do the // lookup. - const RecordType *RT; + CXXRecordDecl *Record = 0; if (getQualifier()) { Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); - RT = T->getAs(); - assert(RT && "qualifier in member expression does not name record"); - + Record = T->getAsCXXRecordDecl(); + assert(Record && "qualifier in member expression does not name record"); + } // Otherwise the naming class must have been the base class. - } else { + else { QualType BaseType = getBaseType().getNonReferenceType(); if (isArrow()) { const PointerType *PT = BaseType->getAs(); @@ -728,11 +745,11 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { BaseType = PT->getPointeeType(); } - RT = BaseType->getAs(); - assert(RT && "base of member expression does not name record"); + Record = BaseType->getAsCXXRecordDecl(); + assert(Record && "base of member expression does not name record"); } - return cast(RT->getDecl()); + return Record; } Stmt::child_iterator UnresolvedMemberExpr::child_begin() { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eeeeb5c..c1a42d8 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -16,7 +16,9 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/Expr.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" @@ -203,6 +205,13 @@ public: return Visit(E->getSubExpr()); } bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } + + // Has side effects if any element does. + bool VisitInitListExpr(InitListExpr *E) { + for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) + if (Visit(E->getInit(i))) return true; + return false; + } }; } // end anonymous namespace @@ -221,7 +230,7 @@ public: APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitDeclRefExpr(DeclRefExpr *E); APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); } @@ -821,6 +830,7 @@ public: bool VisitCallExpr(CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitOffsetOfExpr(const OffsetOfExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); @@ -961,7 +971,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return complex_type_class; else if (ArgTy->isFunctionType()) return function_type_class; - else if (ArgTy->isStructureType()) + else if (ArgTy->isStructureOrClassType()) return record_type_class; else if (ArgTy->isUnionType()) return union_type_class; @@ -1109,9 +1119,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { assert(E->getOpcode() == BinaryOperator::NE && "Invalid complex comparison."); return Success(((CR_r == APFloat::cmpGreaterThan || - CR_r == APFloat::cmpLessThan) && + CR_r == APFloat::cmpLessThan || + CR_r == APFloat::cmpUnordered) || (CR_i == APFloat::cmpGreaterThan || - CR_i == APFloat::cmpLessThan)), E); + CR_i == APFloat::cmpLessThan || + CR_i == APFloat::cmpUnordered)), E); } } else { if (E->getOpcode() == BinaryOperator::EQ) @@ -1154,7 +1166,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(CR == APFloat::cmpEqual, E); case BinaryOperator::NE: return Success(CR == APFloat::cmpGreaterThan - || CR == APFloat::cmpLessThan, E); + || CR == APFloat::cmpLessThan + || CR == APFloat::cmpUnordered, E); } } @@ -1191,8 +1204,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } if (E->getOpcode() == BinaryOperator::Sub) { - const QualType Type = E->getLHS()->getType(); - const QualType ElementType = Type->getAs()->getPointeeType(); + QualType Type = E->getLHS()->getType(); + QualType ElementType = Type->getAs()->getPointeeType(); CharUnits ElementSize = CharUnits::One(); if (!ElementType->isVoidType() && !ElementType->isFunctionType()) @@ -1365,6 +1378,85 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E); } +bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { + CharUnits Result; + unsigned n = E->getNumComponents(); + OffsetOfExpr* OOE = const_cast(E); + if (n == 0) + return false; + QualType CurrentType = E->getTypeSourceInfo()->getType(); + for (unsigned i = 0; i != n; ++i) { + OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: { + Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); + APSInt IdxResult; + if (!EvaluateInteger(Idx, IdxResult, Info)) + return false; + const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType); + if (!AT) + return false; + CurrentType = AT->getElementType(); + CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); + Result += IdxResult.getSExtValue() * ElementSize; + break; + } + + case OffsetOfExpr::OffsetOfNode::Field: { + FieldDecl *MemberDecl = ON.getField(); + const RecordType *RT = CurrentType->getAs(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + unsigned i = 0; + // FIXME: It would be nice if we didn't have to loop here! + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == MemberDecl) + break; + } + assert(i < RL.getFieldCount() && "offsetof field in wrong type"); + Result += CharUnits::fromQuantity( + RL.getFieldOffset(i) / Info.Ctx.getCharWidth()); + CurrentType = MemberDecl->getType().getNonReferenceType(); + break; + } + + case OffsetOfExpr::OffsetOfNode::Identifier: + llvm_unreachable("dependent __builtin_offsetof"); + return false; + + case OffsetOfExpr::OffsetOfNode::Base: { + CXXBaseSpecifier *BaseSpec = ON.getBase(); + if (BaseSpec->isVirtual()) + return false; + + // Find the layout of the class whose base we are looking into. + const RecordType *RT = CurrentType->getAs(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + + // Find the base class itself. + CurrentType = BaseSpec->getType(); + const RecordType *BaseRT = CurrentType->getAs(); + if (!BaseRT) + return false; + + // Add the offset to the base. + Result += CharUnits::fromQuantity( + RL.getBaseClassOffset(cast(BaseRT->getDecl())) + / Info.Ctx.getCharWidth()); + break; + } + } + } + return Success(Result.getQuantity(), E); +} + bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // Special case unary operators that do not need their subexpression // evaluated. offsetof/sizeof/alignof are all special. @@ -1373,12 +1465,12 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // directly Evaluate it as an l-value. APValue LV; if (!EvaluateLValue(E->getSubExpr(), LV, Info)) - return false; + return false; if (LV.getLValueBase()) - return false; + return false; return Success(LV.getLValueOffset().getQuantity(), E); } - + if (E->getOpcode() == UnaryOperator::LNot) { // LNot's operand isn't necessarily an integer, so we handle it specially. bool bres; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 93edb42..3782985 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -15,15 +15,16 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" -#include -#include +#include "llvm/Support/Format.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/MathExtras.h" using namespace clang; -ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) - : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0), - MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), - NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } +ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context) + : Context(Context), Size(0), Alignment(8), Packed(false), + UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false), + NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } /// IsNearlyEmpty - Indicates when a class has a vtable pointer, but /// no other data. @@ -31,29 +32,29 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { // FIXME: Audit the corners if (!RD->isDynamicClass()) return false; - const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); - if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0)) + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); + if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0)) return true; return false; } void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { - const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = - Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo(); - + const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = + Context.getASTRecordLayout(RD).getPrimaryBaseInfo(); + // If the record has a primary base class that is virtual, add it to the set // of primary bases. 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(), - e = RD->bases_end(); i != e; ++i) { + e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - + // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. if (Base->getNumVBases()) @@ -64,10 +65,10 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); @@ -80,12 +81,12 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { /*IsVirtual=*/true); return; } - + // Is this the first nearly empty virtual base? if (!FirstNearlyEmptyVBase) FirstNearlyEmptyVBase = Base; } - + SelectPrimaryVBase(Base); if (PrimaryBase.getBase()) return; @@ -97,11 +98,11 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // If the class isn't dynamic, it won't have a primary base. if (!RD->isDynamicClass()) return; - + // Compute all the primary virtual bases for all of our direct and // indirect bases, and record all their primary virtual base classes. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { + e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot lay out class with dependent bases."); const CXXRecordDecl *Base = @@ -109,15 +110,15 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { IdentifyPrimaryBases(Base); } - // If the record has a dynamic base class, attempt to choose a primary base - // class. It is the first (in direct base class order) non-virtual dynamic + // If the record has a dynamic base class, attempt to choose a primary base + // class. It is the first (in direct base class order) non-virtual dynamic // base class, if one exists. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { + e = RD->bases_end(); i != e; ++i) { // Ignore virtual bases. if (i->isVirtual()) continue; - + const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); @@ -139,44 +140,47 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // Otherwise, it is the first nearly empty virtual base that is not an // indirect primary virtual base class, if one exists. if (FirstNearlyEmptyVBase) { - PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, /*IsVirtual=*/true); return; } - + // Otherwise there is no primary base class. assert(!PrimaryBase.getBase() && "Should not get here with a primary base!"); // Allocate the virtual table pointer at offset zero. assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); - + // Update the size. - Size += Ctx.Target.getPointerWidth(0); + Size += Context.Target.getPointerWidth(0); DataSize = Size; // Update the alignment. - UpdateAlignment(Ctx.Target.getPointerAlign(0)); + UpdateAlignment(Context.Target.getPointerAlign(0)); } void ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { // First, determine the primary base class. DeterminePrimaryBase(RD); - + // If we have a primary base class, lay it out. if (const CXXRecordDecl *Base = PrimaryBase.getBase()) { if (PrimaryBase.isVirtual()) { // We have a virtual primary base, insert it as an indirect primary base. IndirectPrimaryBases.insert(Base); + assert(!VisitedVirtualBases.count(Base) && "vbase already visited!"); + VisitedVirtualBases.insert(Base); + LayoutVirtualBase(Base); } else LayoutNonVirtualBase(Base); } - + // Now lay out the non-virtual bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { // Ignore virtual bases. if (I->isVirtual()) @@ -197,83 +201,113 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { // Layout the base. uint64_t Offset = LayoutBase(RD); - + // Add its base class offset. if (!Bases.insert(std::make_pair(RD, Offset)).second) assert(false && "Added same base offset more than once!"); } -void -ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, +void +ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, const CXXRecordDecl *MostDerivedClass) { + // We already have the offset for the primary base of the most derived class. + if (RD != MostDerivedClass) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // If this is a primary virtual base and we haven't seen it before, add it. + if (PrimaryBase && Layout.getPrimaryBaseWasVirtual() && + !VBases.count(PrimaryBase)) + VBases.insert(std::make_pair(PrimaryBase, Offset)); + } + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + if (!BaseDecl->getNumVBases()) { + // This base isn't interesting since it doesn't have any virtual bases. + continue; + } + + // Compute the offset of this base. + uint64_t BaseOffset; + + if (I->isVirtual()) { + // If we don't know this vbase yet, don't visit it. It will be visited + // later. + if (!VBases.count(BaseDecl)) { + continue; + } + + // Check if we've already visited this base. + if (!VisitedVirtualBases.insert(BaseDecl)) + continue; + + // We want the vbase offset from the class we're currently laying out. + BaseOffset = VBases[BaseDecl]; + } else if (RD == MostDerivedClass) { + // We want the base offset from the class we're currently laying out. + assert(Bases.count(BaseDecl) && "Did not find base!"); + BaseOffset = Bases[BaseDecl]; + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + } + + AddPrimaryVirtualBaseOffsets(BaseDecl, BaseOffset, MostDerivedClass); + } +} + +void +ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *MostDerivedClass) { const CXXRecordDecl *PrimaryBase; + bool PrimaryBaseIsVirtual; - if (MostDerivedClass == RD) + if (MostDerivedClass == RD) { PrimaryBase = this->PrimaryBase.getBase(); - else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual(); + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); PrimaryBase = Layout.getPrimaryBase(); + PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); } for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); if (I->isVirtual()) { - bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); - - // We only want to visit this virtual base if it's either a primary base, - // or not an indirect primary base. - if (Base == PrimaryBase || !IndirectPrimaryBase) { - // Only lay things out once. - if (!VisitedVirtualBases.insert(Base)) - continue; - - if (Base == PrimaryBase) { - assert(IndirectPrimaryBase && - "Base is supposed to be an indirect primary base!"); - - // We only want to add a vbase offset if this primary base is not the - // primary base of the most derived class. - if (PrimaryBase != this->PrimaryBase.getBase() || - !this->PrimaryBase.isVirtual()) { - if (!VBases.insert(std::make_pair(Base, Offset)).second) - assert(false && "Added same vbase offset more than once!"); - } - } else { - // We actually do want to lay out this base. + if (PrimaryBase != Base || !PrimaryBaseIsVirtual) { + bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); + + // Only lay out the virtual base if it's not an indirect primary base. + if (!IndirectPrimaryBase) { + // Only visit virtual bases once. + if (!VisitedVirtualBases.insert(Base)) + continue; + LayoutVirtualBase(Base); } } } - + if (!Base->getNumVBases()) { // This base isn't interesting since it doesn't have any virtual bases. continue; } - // Compute the offset of this base. - uint64_t BaseOffset; - - if (I->isVirtual()) { - // We want the vbase offset from the class we're currently laying out. - assert(VBases.count(Base) && "Did not find virtual base!"); - BaseOffset = VBases[Base]; - } else if (RD == MostDerivedClass) { - // We want the base offset from the class we're currently laying out. - assert(Bases.count(Base) && "Did not find base!"); - BaseOffset = Bases[Base]; - } else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } - - LayoutVirtualBases(Base, BaseOffset, MostDerivedClass); + LayoutVirtualBases(Base, MostDerivedClass); } } @@ -287,7 +321,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { } uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { - const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); // If we have an empty base class, try to place it at offset 0. if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { @@ -298,17 +332,17 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { return 0; } - + unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); - + // Round up the current record size to the base's alignment boundary. uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); - + // Try to place the base. while (true) { if (canPlaceRecordAtOffset(RD, Offset)) break; - + Offset += BaseAlign; } @@ -327,44 +361,44 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { return Offset; } -bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, +bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const { // Look for an empty class with the same type at the same offset. - for (EmptyClassOffsetsTy::const_iterator I = - EmptyClassOffsets.lower_bound(Offset), - E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) { - + for (EmptyClassOffsetsTy::const_iterator I = + EmptyClassOffsets.lower_bound(Offset), + E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) { + if (I->second == RD) return false; } - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); // Check bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); - + if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset)) return false; } - + // Check fields. unsigned FieldNo = 0; - for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); - + if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset)) return false; } @@ -373,35 +407,35 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, return true; } -bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, +bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const { QualType T = FD->getType(); if (const RecordType *RT = T->getAs()) { if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) return canPlaceRecordAtOffset(RD, Offset); } - - if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { - QualType ElemTy = Ctx.getBaseElementType(AT); + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.getBaseElementType(AT); const RecordType *RT = ElemTy->getAs(); if (!RT) return true; const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) return true; - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); - uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { if (!canPlaceRecordAtOffset(RD, ElementOffset)) return false; - + ElementOffset += Info.getSize(); } } - + return true; } @@ -409,39 +443,39 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset) { if (RD->isEmpty()) EmptyClassOffsets.insert(std::make_pair(Offset, RD)); - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); // Update bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); - + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset); } - + // Update fields. unsigned FieldNo = 0; - for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); UpdateEmptyClassOffsets(FD, Offset + FieldOffset); } - + // FIXME: Update virtual bases. } void -ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, +ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset) { QualType T = FD->getType(); @@ -451,19 +485,19 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, return; } } - - if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { - QualType ElemTy = Ctx.getBaseElementType(AT); + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.getBaseElementType(AT); const RecordType *RT = ElemTy->getAs(); if (!RT) return; const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) return; - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); - uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { @@ -495,20 +529,50 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { NonVirtualSize = Size; NonVirtualAlignment = Alignment; - // If this is a C++ class, lay out its virtual bases. - if (RD) - LayoutVirtualBases(RD, 0, RD); + // If this is a C++ class, lay out its virtual bases and add its primary + // virtual base offsets. + if (RD) { + LayoutVirtualBases(RD, RD); + + VisitedVirtualBases.clear(); + AddPrimaryVirtualBaseOffsets(RD, 0, RD); + } // Finally, round the size of the total struct up to the alignment of the // struct itself. FinishLayout(); + +#ifndef NDEBUG + if (RD) { + // Check that we have base offsets for all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); + } + } +#endif } // FIXME. Impl is no longer needed. void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl) { if (ObjCInterfaceDecl *SD = D->getSuperClass()) { - const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD); + const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD); UpdateAlignment(SL.getAlignment()); @@ -528,7 +592,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector Ivars; - Ctx.ShallowCollectObjCIvars(D, Ivars); + Context.ShallowCollectObjCIvars(D, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) LayoutField(Ivars[i]); @@ -541,20 +605,82 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); Field != FieldEnd; ++Field) + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) LayoutField(*Field); } +void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, + uint64_t TypeSize) { + assert(Context.getLangOptions().CPlusPlus && + "Can only have wide bit-fields in C++!"); + + // Itanium C++ ABI 2.4: + // If sizeof(T)*8 < n, let T' be the largest integral POD type with + // sizeof(T')*8 <= n. + + QualType IntegralPODTypes[] = { + Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, + Context.UnsignedLongTy, Context.UnsignedLongLongTy + }; + + QualType Type; + for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes); + I != E; ++I) { + uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]); + + if (Size > FieldSize) + break; + + Type = IntegralPODTypes[I]; + } + assert(!Type.isNull() && "Did not find a type!"); + + unsigned TypeAlign = Context.getTypeAlign(Type); + + // We're not going to use any of the unfilled bits in the last byte. + UnfilledBitsInLastByte = 0; + + uint64_t FieldOffset; + + if (IsUnion) { + DataSize = std::max(DataSize, FieldSize); + FieldOffset = 0; + } else { + // The bitfield is allocated starting at the next offset aligned appropriately + // for T', with length n bits. + FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign); + + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); + UnfilledBitsInLastByte = DataSize - NewSizeInBits; + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Update the size. + Size = std::max(Size, DataSize); + + // Remember max struct/class alignment. + UpdateAlignment(TypeAlign); +} + void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr(); uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); - uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue(); - - std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + + std::pair FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; unsigned FieldAlign = FieldInfo.second; - - if (FieldPacked) + + if (FieldSize > TypeSize) { + LayoutWideBitField(FieldSize, TypeSize); + return; + } + + if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; if (const AlignedAttr *AA = D->getAttr()) FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); @@ -562,33 +688,32 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // 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. + + // 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 + + // 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); } @@ -606,21 +731,21 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { uint64_t FieldOffset = IsUnion ? 0 : DataSize; uint64_t FieldSize; unsigned FieldAlign; - + 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()); + const ArrayType* ATy = Context.getAsArrayType(D->getType()); + FieldAlign = Context.getTypeAlign(ATy->getElementType()); } else if (const ReferenceType *RT = D->getType()->getAs()) { unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Ctx.Target.getPointerWidth(AS); - FieldAlign = Ctx.Target.getPointerAlign(AS); + FieldSize = Context.Target.getPointerWidth(AS); + FieldAlign = Context.Target.getPointerAlign(AS); } else { - std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + std::pair FieldInfo = Context.getTypeInfo(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; } @@ -636,20 +761,20 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { // 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; } - + UpdateEmptyClassOffsets(D, FieldOffset); } - + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); @@ -668,7 +793,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { void ASTRecordLayoutBuilder::FinishLayout() { // In C++, records cannot be of size 0. - if (Ctx.getLangOptions().CPlusPlus && Size == 0) + if (Context.getLangOptions().CPlusPlus && Size == 0) Size = 8; // Finally, round the size of the record up to the alignment of the // record itself. @@ -735,7 +860,7 @@ const CXXMethodDecl * ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { assert(RD->isDynamicClass() && "Class does not have any virtual methods!"); - // If a class isnt' polymorphic it doesn't have a key function. + // If a class isn't polymorphic it doesn't have a key function. if (!RD->isPolymorphic()) return 0; @@ -745,13 +870,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace()) return 0; - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { + 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; @@ -759,17 +884,134 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { // they don't have a body until they're defined. if (MD->isImplicit()) continue; - + if (MD->isInlineSpecified()) continue; if (MD->hasInlineBody()) continue; - + // We found it. return MD; } - + return 0; } +static void PrintOffset(llvm::raw_ostream &OS, + uint64_t Offset, unsigned IndentLevel) { + OS << llvm::format("%4d | ", Offset); + OS.indent(IndentLevel * 2); +} + +static void DumpCXXRecordLayout(llvm::raw_ostream &OS, + const CXXRecordDecl *RD, ASTContext &C, + uint64_t Offset, + unsigned IndentLevel, + const char* Description, + bool IncludeVirtualBases) { + const ASTRecordLayout &Info = C.getASTRecordLayout(RD); + + PrintOffset(OS, Offset, IndentLevel); + OS << C.getTypeDeclType(const_cast(RD)).getAsString(); + if (Description) + OS << ' ' << Description; + if (RD->isEmpty()) + OS << " (empty)"; + OS << '\n'; + + IndentLevel++; + + const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); + + // Vtable pointer. + if (RD->isDynamicClass() && !PrimaryBase) { + PrintOffset(OS, Offset, IndentLevel); + OS << '(' << RD << " vtable pointer)\n"; + } + // Dump (non-virtual) bases + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8; + + DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel, + Base == PrimaryBase ? "(primary base)" : "(base)", + /*IncludeVirtualBases=*/false); + } + + // Dump fields. + uint64_t FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *Field = *I; + uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8; + + if (const RecordType *RT = Field->getType()->getAs()) { + if (const CXXRecordDecl *D = dyn_cast(RT->getDecl())) { + DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel, + Field->getNameAsCString(), + /*IncludeVirtualBases=*/true); + continue; + } + } + + PrintOffset(OS, FieldOffset, IndentLevel); + OS << Field->getType().getAsString() << ' ' << Field << '\n'; + } + + if (!IncludeVirtualBases) + return; + + // Dump virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + assert(I->isVirtual() && "Found non-virtual class!"); + const CXXRecordDecl *VBase = + cast(I->getType()->getAs()->getDecl()); + + uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8; + DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, + VBase == PrimaryBase ? + "(primary virtual base)" : "(virtual base)", + /*IncludeVirtualBases=*/false); + } + + OS << " sizeof=" << Info.getSize() / 8; + OS << ", dsize=" << Info.getDataSize() / 8; + OS << ", align=" << Info.getAlignment() / 8 << '\n'; + OS << " nvsize=" << Info.getNonVirtualSize() / 8; + OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n'; + OS << '\n'; +} + +void ASTContext::DumpRecordLayout(const RecordDecl *RD, + llvm::raw_ostream &OS) { + const ASTRecordLayout &Info = getASTRecordLayout(RD); + + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) + return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0, + /*IncludeVirtualBases=*/true); + + OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n"; + OS << "Record: "; + RD->dump(); + OS << "\nLayout: "; + OS << "\n"; +} diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index a4bce75..f277c29 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -26,7 +26,7 @@ namespace clang { class RecordDecl; class ASTRecordLayoutBuilder { - ASTContext &Ctx; + ASTContext &Context; /// Size - The current size of the record layout. uint64_t Size; @@ -91,6 +91,7 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); void LayoutBitField(const FieldDecl *D); /// DeterminePrimaryBase - Determine the primary base of the given class. @@ -112,8 +113,11 @@ class ASTRecordLayoutBuilder { /// LayoutNonVirtualBase - Lays out a single non-virtual base. void LayoutNonVirtualBase(const CXXRecordDecl *RD); + void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, + const CXXRecordDecl *MostDerivedClass); + /// LayoutVirtualBases - Lays out all the virtual bases. - void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset, + void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass); /// LayoutVirtualBase - Lays out a single virtual base. diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 9702382..67fd74c 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Type.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/Basic/TargetInfo.h" #include using namespace clang; @@ -240,6 +241,8 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, // asm string. std::string CurStringPiece; + bool HasVariants = !C.Target.hasNoAsmVariants(); + while (1) { // Done with the string? if (CurPtr == StrEnd) { @@ -251,9 +254,9 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, char CurChar = *CurPtr++; switch (CurChar) { case '$': CurStringPiece += "$$"; continue; - case '{': CurStringPiece += "$("; continue; - case '|': CurStringPiece += "$|"; continue; - case '}': CurStringPiece += "$)"; continue; + case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; + case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; + case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; case '%': break; default: @@ -389,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, RParenLoc = RPL; } - -ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, - SourceLocation rparenloc, - ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, - Stmt *atCatchList) -: Stmt(ObjCAtCatchStmtClass) { - ExceptionDecl = catchVarDecl; - SubExprs[BODY] = atCatchStmt; - SubExprs[NEXT_CATCH] = NULL; - // FIXME: O(N^2) in number of catch blocks. - if (atCatchList) { - ObjCAtCatchStmt *AtCatchList = static_cast(atCatchList); - - while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) - AtCatchList = NextCatch; - - AtCatchList->SubExprs[NEXT_CATCH] = this; - } - AtCatchLoc = atCatchLoc; - RParenLoc = rparenloc; +ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt) + : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc), + NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0) +{ + Stmt **Stmts = getStmts(); + Stmts[0] = atTryStmt; + for (unsigned I = 0; I != NumCatchStmts; ++I) + Stmts[I + 1] = CatchStmts[I]; + + if (HasFinally) + Stmts[NumCatchStmts + 1] = atFinallyStmt; +} + +ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, + SourceLocation atTryLoc, + Stmt *atTryStmt, + Stmt **CatchStmts, + unsigned NumCatchStmts, + Stmt *atFinallyStmt) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignof()); + return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, + atFinallyStmt); +} + +ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignof()); + return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); +} + +SourceRange ObjCAtTryStmt::getSourceRange() const { + SourceLocation EndLoc; + if (HasFinally) + EndLoc = getFinallyStmt()->getLocEnd(); + else if (NumCatchStmts) + EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd(); + else + EndLoc = getTryBody()->getLocEnd(); + + return SourceRange(AtTryLoc, EndLoc); } CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, @@ -627,19 +657,18 @@ Stmt::child_iterator AsmStmt::child_end() { } // ObjCAtCatchStmt -Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ObjCAtCatchStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} +Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; } +Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; } // ObjCAtFinallyStmt Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } // ObjCAtTryStmt -Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; } -Stmt::child_iterator ObjCAtTryStmt::child_end() { - return &SubStmts[0]+END_EXPR; +Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); } + +Stmt::child_iterator ObjCAtTryStmt::child_end() { + return getStmts() + 1 + NumCatchStmts + HasFinally; } // ObjCAtThrowStmt diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index ba6218b..ca62ed1 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -143,6 +143,7 @@ namespace { void DumpCXXTemporary(CXXTemporary *Temporary); // ObjC + void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); @@ -219,7 +220,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // nodes are where they need to be. if (TypedefDecl *localType = dyn_cast(D)) { OS << "\"typedef " << localType->getUnderlyingType().getAsString() - << " " << localType->getNameAsString() << "\""; + << ' ' << localType << '"'; } else if (ValueDecl *VD = dyn_cast(D)) { OS << "\""; // Emit storage class for vardecls. @@ -299,9 +300,35 @@ void StmtDumper::VisitExpr(Expr *Node) { DumpExpr(Node); } +static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) { + if (Node->getBasePath().empty()) + return; + + OS << " ("; + bool First = true; + for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(), + E = Node->getBasePath().end(); I != E; ++I) { + const CXXBaseSpecifier *Base = *I; + if (!First) + OS << " -> "; + + const CXXRecordDecl *RD = + cast(Base->getType()->getAs()->getDecl()); + + if (Base->isVirtual()) + OS << "virtual "; + OS << RD->getName(); + First = false; + } + + OS << ')'; +} + void StmtDumper::VisitCastExpr(CastExpr *Node) { DumpExpr(Node); - OS << " <" << Node->getCastKindName() << ">"; + OS << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; } void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { @@ -328,15 +355,14 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { case Decl::ObjCClass: OS << "ObjCClass"; break; } - OS << "='" << Node->getDecl()->getNameAsString() - << "' " << (void*)Node->getDecl(); + OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl(); } void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { DumpExpr(Node); OS << " ("; if (!Node->requiresADL()) OS << "no "; - OS << "ADL) = '" << Node->getName().getAsString() << "'"; + OS << "ADL) = '" << Node->getName() << '\''; UnresolvedLookupExpr::decls_iterator I = Node->decls_begin(), E = Node->decls_end(); @@ -349,7 +375,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); OS << " " << Node->getDecl()->getDeclKindName() - << "Decl='" << Node->getDecl()->getNameAsString() + << "Decl='" << Node->getDecl() << "' " << (void*)Node->getDecl(); if (Node->isFreeIvar()) OS << " isFreeIvar"; @@ -408,7 +434,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") - << Node->getMemberDecl()->getNameAsString() << " " + << Node->getMemberDecl() << ' ' << (void*)Node->getMemberDecl(); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { @@ -452,7 +478,9 @@ void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); OS << " " << Node->getCastName() << "<" << Node->getTypeAsWritten().getAsString() << ">" - << " <" << Node->getCastKindName() << ">"; + << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { @@ -506,8 +534,33 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); OS << " selector=" << Node->getSelector().getAsString(); - if (IdentifierInfo *clsName = Node->getClassName()) - OS << " class=" << clsName->getNameStart(); + switch (Node->getReceiverKind()) { + case ObjCMessageExpr::Instance: + break; + + case ObjCMessageExpr::Class: + OS << " class="; + DumpType(Node->getClassReceiver()); + break; + + case ObjCMessageExpr::SuperInstance: + OS << " super (instance)"; + break; + + case ObjCMessageExpr::SuperClass: + OS << " super (class)"; + break; + } +} + +void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) { + DumpStmt(Node); + if (VarDecl *CatchParam = Node->getCatchParamDecl()) { + OS << " catch parm = "; + DumpDeclarator(CatchParam); + } else { + OS << " catch all"; + } } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { @@ -525,14 +578,13 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - OS << " " << Node->getProtocol()->getNameAsString(); + OS << ' ' << Node->getProtocol(); } void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - OS << " Kind=PropertyRef Property=\"" - << Node->getProperty()->getNameAsString() << "\""; + OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"'; } void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index da43878..52f627d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Format.h" +#include "clang/AST/Expr.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -388,11 +389,8 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { OS << "\n"; } - for (ObjCAtCatchStmt *catchStmt = - static_cast(Node->getCatchStmts()); - catchStmt; - catchStmt = - static_cast(catchStmt->getNextCatchStmt())) { + for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I); Indent() << "@catch("; if (catchStmt->getCatchParamDecl()) { if (Decl *DS = catchStmt->getCatchParamDecl()) @@ -474,7 +472,7 @@ void StmtPrinter::VisitExpr(Expr *Node) { void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); if (Node->hasExplicitTemplateArgumentList()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), @@ -509,7 +507,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); } void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { @@ -527,7 +525,7 @@ void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( OS << "."; } if (Node->getGetterMethod()) - OS << Node->getGetterMethod()->getNameAsString(); + OS << Node->getGetterMethod(); } @@ -695,7 +693,7 @@ bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { } else { MemberExpr *ME = cast(E); bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); - OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString(); + OS << (IsFirst ? "" : ".") << ME->getMemberDecl(); return false; } } @@ -706,6 +704,39 @@ void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { OS << ")"; } +void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { + OS << "__builtin_offsetof("; + OS << Node->getTypeSourceInfo()->getType().getAsString() << ", "; + bool PrintedSomething = false; + for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) { + OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i); + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) { + // Array node + OS << "["; + PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex())); + OS << "]"; + PrintedSomething = true; + continue; + } + + // Skip implicit base indirections. + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base) + continue; + + // Field or identifier node. + IdentifierInfo *Id = ON.getFieldName(); + if (!Id) + continue; + + if (PrintedSomething) + OS << "."; + else + PrintedSomething = true; + OS << Id->getName(); + } + OS << ")"; +} + void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); if (Node->isArgumentType()) @@ -746,7 +777,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getMemberDecl()->getNameAsString(); + OS << Node->getMemberDecl(); if (Node->hasExplicitTemplateArgumentList()) OS << TemplateSpecializationType::PrintTemplateArgumentList( @@ -1242,14 +1273,26 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { } void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')'; + OS << "@protocol(" << Node->getProtocol() << ')'; } void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "["; - Expr *receiver = Mess->getReceiver(); - if (receiver) PrintExpr(receiver); - else OS << Mess->getClassName()->getName(); + switch (Mess->getReceiverKind()) { + case ObjCMessageExpr::Instance: + PrintExpr(Mess->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + OS << Mess->getClassReceiver().getAsString(Policy); + break; + + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + OS << "Super"; + break; + } + OS << ' '; Selector selector = Mess->getSelector(); if (selector.isUnarySelector()) { @@ -1304,7 +1347,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { } void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); } //===----------------------------------------------------------------------===// // Stmt method implementations diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 3a19ec2..d45bb2f 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -261,6 +261,34 @@ void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { ID.AddInteger(S->getOpcode()); } +void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) { + VisitType(S->getTypeSourceInfo()->getType()); + unsigned n = S->getNumComponents(); + for (unsigned i = 0; i < n; ++i) { + const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i); + ID.AddInteger(ON.getKind()); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: + // Expressions handled below. + break; + + case OffsetOfExpr::OffsetOfNode::Field: + VisitDecl(ON.getField()); + break; + + case OffsetOfExpr::OffsetOfNode::Identifier: + ID.AddPointer(ON.getFieldName()); + break; + + case OffsetOfExpr::OffsetOfNode::Base: + // These nodes are implicit, and therefore don't need profiling. + break; + } + } + + VisitExpr(S); +} + void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { VisitExpr(S); ID.AddBoolean(S->isSizeOf()); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index b56c0ceb..14722f7 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -15,9 +15,11 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using namespace llvm; TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast()) @@ -45,13 +47,13 @@ void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast()) - OS << Template->getNameAsString(); + OS << Template; else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << QTN->getDecl()->getNameAsString(); + OS << QTN->getDecl(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); @@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, } } +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + TemplateName N) { + std::string NameStr; + raw_string_ostream OS(NameStr); + LangOptions LO; + LO.CPlusPlus = true; + LO.Bool = true; + N.print(OS, PrintingPolicy(LO)); + OS.flush(); + return DB << NameStr; +} + void TemplateName::dump() const { LangOptions LO; // FIXME! LO.CPlusPlus = true; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 27a277d..05e7fdc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -225,6 +225,11 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isStructureOrClassType() const { + if (const RecordType *RT = getAs()) + return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return false; +} bool Type::isVoidPointerType() const { if (const PointerType *PT = getAs()) return PT->getPointeeType()->isVoidType(); @@ -410,6 +415,16 @@ const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { return 0; } +CXXRecordDecl *Type::getAsCXXRecordDecl() const { + if (const RecordType *RT = getAs()) + return dyn_cast(RT->getDecl()); + else if (const InjectedClassNameType *Injected + = getAs()) + return Injected->getDecl(); + + return 0; +} + bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && @@ -999,12 +1014,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { TemplateSpecializationType:: TemplateSpecializationType(ASTContext &Context, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), - Context(Context), + ContextAndCurrentInstantiation(&Context, IsCurrentInstantiation), Template(T), NumArgs(NumArgs) { assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && @@ -1039,9 +1055,11 @@ TemplateSpecializationType::getArg(unsigned Idx) const { void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, ASTContext &Context) { + ID.AddBoolean(IsCurrentInstantiation); T.Profile(ID); for (unsigned Idx = 0; Idx < NumArgs; ++Idx) Args[Idx].Profile(ID, Context); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 340e373..915d7af 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -29,7 +29,7 @@ namespace { public: explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } - + void Print(QualType T, std::string &S); void AppendScope(DeclContext *DC, std::string &S); void PrintTag(TagDecl *T, std::string &S); @@ -546,7 +546,7 @@ void TypePrinter::PrintTemplateSpecialization( void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, std::string &S) { - PrintTemplateSpecialization(T->getUnderlyingTST(), S); + PrintTemplateSpecialization(T->getInjectedTST(), S); } void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index f94f6b3..7f71e0a 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -46,7 +46,7 @@ public: AddStmtChoice(Kind kind) : k(kind) {} bool alwaysAdd() const { return (unsigned)k & 0x1; } - bool asLValue() const { return k >= AlwaysAddAsLValue; } + bool asLValue() const { return k >= AsLValueNotAlwaysAdd; } private: Kind k; @@ -108,16 +108,16 @@ private: CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); + CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); + CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); CFGBlock *VisitCompoundStmt(CompoundStmt *C); - CFGBlock *VisitConditionalOperator(ConditionalOperator *C, - AddStmtChoice asc); + CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); - CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); - CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); - CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -127,6 +127,7 @@ private: CFGBlock *VisitIfStmt(IfStmt *I); CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); CFGBlock *VisitLabelStmt(LabelStmt *L); + CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); @@ -337,6 +338,10 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) { /// DeclStmts (which may contain nested control-flow). CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { tryAgain: + if (!S) { + badCFG = true; + return 0; + } switch (S->getStmtClass()) { default: return VisitStmt(S, asc); @@ -374,6 +379,9 @@ tryAgain: case Stmt::CXXCatchStmtClass: return VisitCXXCatchStmt(cast(S)); + case Stmt::CXXMemberCallExprClass: + return VisitCXXMemberCallExpr(cast(S), asc); + case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast(S)); @@ -404,6 +412,9 @@ tryAgain: case Stmt::LabelStmtClass: return VisitLabelStmt(cast(S)); + case Stmt::MemberExprClass: + return VisitMemberExpr(cast(S), asc); + case Stmt::ObjCAtCatchStmtClass: return VisitObjCAtCatchStmt(cast(S)); @@ -491,8 +502,16 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, Succ = ConfluenceBlock; Block = NULL; CFGBlock* RHSBlock = addStmt(B->getRHS()); - if (!FinishBlock(RHSBlock)) - return 0; + + if (RHSBlock) { + if (!FinishBlock(RHSBlock)) + return 0; + } + else { + // Create an empty block for cases where the RHS doesn't require + // any explicit statements in the CFG. + RHSBlock = createBlock(); + } // See if this is a known constant. TryResult KnownVal = TryEvaluateBool(B->getLHS()); @@ -627,15 +646,18 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, if (!FinishBlock(ConfluenceBlock)) return 0; + asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + Succ = ConfluenceBlock; Block = NULL; - CFGBlock* LHSBlock = addStmt(C->getLHS()); + CFGBlock* LHSBlock = addStmt(C->getLHS(), asc); if (!FinishBlock(LHSBlock)) return 0; Succ = ConfluenceBlock; Block = NULL; - CFGBlock* RHSBlock = addStmt(C->getRHS()); + CFGBlock* RHSBlock = addStmt(C->getRHS(), asc); if (!FinishBlock(RHSBlock)) return 0; @@ -676,6 +698,9 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, if (!FinishBlock(ConfluenceBlock)) return 0; + asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + // Create a block for the LHS expression if there is an LHS expression. A // GCC extension allows LHS to be NULL, causing the condition to be the // value that is returned instead. @@ -684,7 +709,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, Block = NULL; CFGBlock* LHSBlock = NULL; if (C->getLHS()) { - LHSBlock = addStmt(C->getLHS()); + LHSBlock = addStmt(C->getLHS(), asc); if (!FinishBlock(LHSBlock)) return 0; Block = NULL; @@ -692,7 +717,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, // Create the block for the RHS expression. Succ = ConfluenceBlock; - CFGBlock* RHSBlock = addStmt(C->getRHS()); + CFGBlock* RHSBlock = addStmt(C->getRHS(), asc); if (!FinishBlock(RHSBlock)) return 0; @@ -1074,6 +1099,16 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { } } +CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { + if (asc.alwaysAdd()) { + autoCreateBlock(); + AppendStmt(Block, M, asc); + } + return Visit(M->getBase(), + M->isArrow() ? AddStmtChoice::NotAlwaysAdd + : AddStmtChoice::AsLValueNotAlwaysAdd); +} + CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // Objective-C fast enumeration 'for' statements: // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC @@ -1694,6 +1729,15 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } +CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, + AddStmtChoice asc) { + AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + autoCreateBlock(); + AppendStmt(Block, C, AddStmtChoice(K)); + return VisitChildren(C); +} + CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { // Lazily create the indirect-goto dispatch block if there isn't one already. CFGBlock* IBlock = cfg->getIndirectGotoBlock(); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 2b7fcd0..1870195 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -11,24 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/PartialDiagnostic.h" - -#include "clang/Lex/LexDiagnostic.h" -#include "clang/Parse/ParseDiagnostic.h" #include "clang/AST/ASTDiagnostic.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Analysis/AnalysisDiagnostic.h" -#include "clang/Driver/DriverDiagnostic.h" - +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" + #include #include #include @@ -223,9 +223,12 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ErrorOccurred = false; FatalErrorOccurred = false; - NumDiagnostics = 0; - + ErrorLimit = 0; + TemplateBacktraceLimit = 0; + + NumWarnings = 0; NumErrors = 0; + NumErrorsSuppressed = 0; CustomDiagInfo = 0; CurDiagID = ~0U; LastDiagLevel = Ignored; @@ -286,11 +289,18 @@ bool Diagnostic::isBuiltinNote(unsigned DiagID) { } /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic -/// ID is for an extension of some sort. +/// ID is for an extension of some sort. This also returns EnabledByDefault, +/// which is set to indicate whether the diagnostic is ignored by default (in +/// which case -pedantic enables it) or treated as a warning/error by default. /// -bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) { - return DiagID < diag::DIAG_UPPER_LIMIT && - getBuiltinDiagClass(DiagID) == CLASS_EXTENSION; +bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID, + bool &EnabledByDefault) { + if (DiagID >= diag::DIAG_UPPER_LIMIT || + getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) + return false; + + EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE; + return true; } @@ -529,8 +539,14 @@ bool Diagnostic::ProcessDiag() { // If a fatal error has already been emitted, silence all subsequent // diagnostics. - if (FatalErrorOccurred) + if (FatalErrorOccurred) { + if (DiagLevel >= Diagnostic::Error) { + ++NumErrors; + ++NumErrorsSuppressed; + } + return false; + } // If the client doesn't care about this message, don't issue it. If this is // a note and the last real diagnostic was ignored, ignore it too. @@ -551,11 +567,20 @@ bool Diagnostic::ProcessDiag() { if (DiagLevel >= Diagnostic::Error) { ErrorOccurred = true; ++NumErrors; + + // If we've emitted a lot of errors, emit a fatal error after it to stop a + // flood of bogus errors. + if (ErrorLimit && NumErrors >= ErrorLimit && + DiagLevel == Diagnostic::Error) + SetDelayedDiagnostic(diag::fatal_too_many_errors); } // Finally, report it. Client->HandleDiagnostic(DiagLevel, Info); - if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; + if (Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == Diagnostic::Warning) + ++NumWarnings; + } CurDiagID = ~0U; @@ -1026,8 +1051,15 @@ static void WriteSourceLocation(llvm::raw_ostream &OS, Location = SM->getInstantiationLoc(Location); std::pair Decomposed = SM->getDecomposedLoc(Location); - - WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName()); + + const FileEntry *FE = SM->getFileEntryForID(Decomposed.first); + if (FE) + WriteString(OS, FE->getName()); + else { + // Fallback to using the buffer name when there is no entry. + WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier()); + } + WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second)); WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second)); } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 3da19ca..ed0de8c 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -78,9 +78,9 @@ namespace { /// identifiers because they are language keywords. This causes the lexer to /// automatically map matching identifiers to specialized token codes. /// -/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be +/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be /// enabled in the specified langauge, set to 1 if it is an extension -/// in the specified language, and set to 2 if disabled in the +/// in the specified language, and set to 0 if disabled in the /// specified language. static void AddKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, @@ -90,7 +90,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2; else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; - else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1; + else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1; else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 27cb9be..3ecab1d 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -60,6 +60,8 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { } const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, + const SourceManager &SM, + SourceLocation Loc, bool *Invalid) const { if (Invalid) *Invalid = false; @@ -94,22 +96,67 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, Entry->getName(), ErrorStr); else - Diag.Report(diag::err_cannot_open_file) + Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file) << Entry->getName() << ErrorStr; Buffer.setInt(true); + + // FIXME: This conditionalization is horrible, but we see spurious failures + // in the test suite due to this warning and no one has had time to hunt it + // down. So for now, we just don't emit this diagnostic on Win32, and hope + // nothing bad happens. + // + // PR6812. +#if !defined(LLVM_ON_WIN32) } else if (FileInfo.st_size != Entry->getSize() || FileInfo.st_mtime != Entry->getModificationTime()) { - // Check that the file's size, modification time, and inode are - // the same as in the file entry (which may have come from a - // stat cache). + // Check that the file's size and modification time are the same + // as in the file entry (which may have come from a stat cache). if (Diag.isDiagnosticInFlight()) - Diag.SetDelayedDiagnostic(diag::err_file_modified, + Diag.SetDelayedDiagnostic(diag::err_file_modified, Entry->getName()); - else - Diag.Report(diag::err_file_modified) << Entry->getName(); + else + Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified) + << Entry->getName(); Buffer.setInt(true); +#endif + } + + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + if (!Buffer.getInt()) { + llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); + const char *BOM = 0; + if (BufStr.startswith("\xFE\xBB\xBF")) + BOM = "UTF-8"; + else if (BufStr.startswith("\xFE\xFF")) + BOM = "UTF-16 (BE)"; + else if (BufStr.startswith("\xFF\xFE")) + BOM = "UTF-16 (LE)"; + else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4))) + BOM = "UTF-32 (BE)"; + else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4))) + BOM = "UTF-32 (LE)"; + else if (BufStr.startswith("\x2B\x2F\x76")) + BOM = "UTF-7"; + else if (BufStr.startswith("\xF7\x64\x4C")) + BOM = "UTF-1"; + else if (BufStr.startswith("\xDD\x73\x66\x73")) + BOM = "UTF-EBCDIC"; + else if (BufStr.startswith("\x0E\xFE\xFF")) + BOM = "SDSU"; + else if (BufStr.startswith("\xFB\xEE\x28")) + BOM = "BOCU-1"; + else if (BufStr.startswith("\x84\x31\x95\x33")) + BOM = "BOCU-1"; + + if (BOM) { + Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom) + << BOM << Entry->getName(); + Buffer.setInt(1); + } } } @@ -470,7 +517,7 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File, bool *Invalid) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); assert(IR && "getOrCreateContentCache() cannot return NULL"); - return IR->getBuffer(Diag, Invalid); + return IR->getBuffer(Diag, *this, SourceLocation(), Invalid); } bool SourceManager::overrideFileContents(const FileEntry *SourceFile, @@ -717,8 +764,8 @@ const char *SourceManager::getCharacterData(SourceLocation SL, // Note that calling 'getBuffer()' may lazily page in a source file. bool CharDataInvalid = false; const llvm::MemoryBuffer *Buffer - = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag, - &CharDataInvalid); + = getSLocEntry(LocInfo.first).getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); @@ -757,14 +804,16 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc, return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } -static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag, - ContentCache* FI, - llvm::BumpPtrAllocator &Alloc, - bool &Invalid); -static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI, - llvm::BumpPtrAllocator &Alloc, bool &Invalid) { +static DISABLE_INLINE void +ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid); +static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid) { // Note that calling 'getBuffer()' may lazily page in the file. - const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid); + const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(), + &Invalid); if (Invalid) return; @@ -825,7 +874,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; - ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); if (Invalid) *Invalid = MyInvalid; if (MyInvalid) @@ -991,8 +1040,11 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // To get the source name, first consult the FileEntry (if one exists) // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. - const char *Filename = - C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier(); + const char *Filename; + if (C->Entry) + Filename = C->Entry->getName(); + else + Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second); unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second); SourceLocation IncludeLoc = FI.getIncludeLoc(); @@ -1050,7 +1102,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; - ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); if (MyInvalid) return SourceLocation(); } @@ -1082,15 +1134,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, return SourceLocation(); if (Line > Content->NumLines) { - unsigned Size = Content->getBuffer(Diag)->getBufferSize(); + unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize(); if (Size > 0) --Size; return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size); } unsigned FilePos = Content->SourceLineCache[Line - 1]; - const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos; - unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf; + const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos; + unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf; unsigned i = 0; // Check that the given column is valid. diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 136089f..4c0c59a 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -20,10 +20,10 @@ using namespace clang; // TargetInfo Constructor. TargetInfo::TargetInfo(const std::string &T) : Triple(T) { - // Set defaults. Defaults are set for a 32-bit RISC platform, - // like PPC or SPARC. - // These should be overridden by concrete targets as needed. + // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or + // SPARC. These should be overridden by concrete targets as needed. TLSSupported = true; + NoAsmVariants = false; PointerWidth = PointerAlign = 32; IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; @@ -45,6 +45,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Char32Type = UnsignedInt; Int64Type = SignedLongLong; SigAtomicType = SignedInt; + UseBitFieldTypeAlignment = true; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; @@ -142,9 +143,10 @@ bool TargetInfo::isTypeSigned(IntType T) const { /// Apply changes to the target information with respect to certain /// language options which change the target configuration. void TargetInfo::setForcedLangOptions(LangOptions &Opts) { - if (Opts.ShortWChar) { + if (Opts.NoBitFieldTypeAlign) + UseBitFieldTypeAlignment = false; + if (Opts.ShortWChar) WCharType = UnsignedShort; - } } //===----------------------------------------------------------------------===// diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1797804..3d5048c 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -219,6 +219,8 @@ protected: Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); } public: LinuxTargetInfo(const std::string& triple) @@ -1221,6 +1223,27 @@ public: Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Haiku target +class HaikuX86_32TargetInfo : public X86_32TargetInfo { +public: + HaikuX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__HAIKU__"); } }; } // end anonymous namespace @@ -1373,6 +1396,10 @@ public: SizeType = UnsignedInt; PtrDiffType = SignedInt; + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + // FIXME: Should we just treat this as a feature? IsThumb = getTriple().getArchName().startswith("thumb"); if (IsThumb) { @@ -1397,6 +1424,10 @@ public: DoubleAlign = LongLongAlign = LongDoubleAlign = 32; SizeType = UnsignedLong; + // Do not respect the alignment of bit-field types when laying out + // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. + UseBitFieldTypeAlignment = false; + if (IsThumb) { DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" @@ -2351,6 +2382,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new MinGWX86_32TargetInfo(T); case llvm::Triple::Win32: return new VisualStudioWindowsX86_32TargetInfo(T); + case llvm::Triple::Haiku: + return new HaikuX86_32TargetInfo(T); default: return new X86_32TargetInfo(T); } diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index 810d0fb..e7275ca 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -31,13 +31,22 @@ using namespace clang; static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { - const Expr* Receiver = ME->getReceiver(); - - if (!Receiver) - return NULL; + QualType T; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + T = ME->getInstanceReceiver()->getType(); + break; + + case ObjCMessageExpr::SuperInstance: + T = ME->getSuperType(); + break; + + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + return 0; + } - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs()) + if (const ObjCObjectPointerType *PT = T->getAs()) return PT->getInterfaceType(); return NULL; @@ -509,11 +518,21 @@ public: void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { - - const IdentifierInfo *ClsName = ME->getClassName(); - if (!ClsName) + ObjCInterfaceDecl *Class = 0; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Class: + Class = ME->getClassReceiver()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::SuperClass: + Class = ME->getSuperType()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::Instance: + case ObjCMessageExpr::SuperInstance: return; - + } + Selector S = ME->getSelector(); if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; @@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, llvm::raw_svector_ostream os(buf); os << "The '" << S.getAsString() << "' message should be sent to instances " - "of class '" << ClsName->getName() + "of class '" << Class->getName() << "' and not the class directly"; RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 7c53991..34470af 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -401,7 +401,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, const VarDecl *VD = VR->getDecl(); // BasicStore does not model arrays and structs. - if (VD->getType()->isArrayType() || VD->getType()->isStructureType()) + if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType()) return store; if (VD->hasGlobalStorage()) { diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 4475872..3bcc03f 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -607,7 +607,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (D) { GetRawInt = false; - os << D->getNameAsString(); + os << D; } } diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 06cee5b..776e12b 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) { } const Stmt* -clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){ - const Stmt *S = N->getLocationAs()->getStmt(); - if (const ObjCMessageExpr *ME = dyn_cast(S)) - return ME->getReceiver(); - return NULL; -} - -const Stmt* clang::bugreporter::GetDenomExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs()->getStmt(); if (const BinaryOperator *BE = dyn_cast(S)) @@ -144,7 +136,7 @@ public: if (const DeclStmt *DS = PS->getStmtAs()) { if (const VarRegion *VR = dyn_cast(R)) { - os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; + os << "Variable '" << VR->getDecl() << "' "; } else return NULL; @@ -206,7 +198,7 @@ public: return NULL; if (const VarRegion *VR = dyn_cast(R)) { - os << '\'' << VR->getDecl()->getNameAsString() << '\''; + os << '\'' << VR->getDecl() << '\''; } else return NULL; @@ -402,7 +394,7 @@ public: const ObjCMessageExpr *ME = P->getStmtAs(); if (!ME) return 0; - const Expr *Receiver = ME->getReceiver(); + const Expr *Receiver = ME->getInstanceReceiver(); if (!Receiver) return 0; const GRState *state = N->getState(); diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 3c4a27c..d26ee1d 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -603,12 +603,33 @@ public: Selector S = ME->getSelector(); - if (Expr* Receiver = ME->getReceiver()) { - const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); - return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; + const ObjCInterfaceDecl* OD = 0; + bool IsInstanceMessage = false; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + OD = getReceiverDecl(ME->getInstanceReceiver()); + IsInstanceMessage = true; + break; + + case ObjCMessageExpr::SuperInstance: + IsInstanceMessage = true; + OD = ME->getSuperType()->getAs() + ->getInterfaceDecl(); + break; + + case ObjCMessageExpr::Class: + OD = ME->getClassReceiver()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::SuperClass: + OD = ME->getSuperType()->getAs()->getDecl(); + break; } - return M[ObjCSummaryKey(ME->getClassName(), S)]; + if (IsInstanceMessage) + return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; + + return M[ObjCSummaryKey(OD->getIdentifier(), S)]; } RetainSummary*& operator[](ObjCSummaryKey K) { @@ -836,7 +857,7 @@ public: RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME, const ObjCInterfaceDecl* ID) { - return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), + return getInstanceMethodSummary(ME->getSelector(), 0, ID, ME->getMethodDecl(), ME->getType()); } @@ -851,8 +872,21 @@ public: QualType RetTy); RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { - return getClassMethodSummary(ME->getSelector(), ME->getClassName(), - ME->getClassInfo().Decl, + ObjCInterfaceDecl *Class = 0; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + Class = ME->getReceiverInterface(); + break; + + case ObjCMessageExpr::Instance: + case ObjCMessageExpr::SuperInstance: + break; + } + + return getClassMethodSummary(ME->getSelector(), + Class? Class->getIdentifier() : 0, + Class, ME->getMethodDecl(), ME->getType()); } @@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, // We need the type-information of the tracked receiver object // Retrieve it from the state. - const Expr *Receiver = ME->getReceiver(); + const Expr *Receiver = ME->getInstanceReceiver(); const ObjCInterfaceDecl* ID = 0; // FIXME: Is this really working as expected? There are cases where // we just use the 'ID' from the message expression. - SVal receiverV = state->getSValAsScalarOrLoc(Receiver); + SVal receiverV; + + if (const Expr *Receiver = ME->getInstanceReceiver()) { + receiverV = state->getSValAsScalarOrLoc(Receiver); - // FIXME: Eventually replace the use of state->get with - // a generic API for reasoning about the Objective-C types of symbolic - // objects. - if (SymbolRef Sym = receiverV.getAsLocSymbol()) - if (const RefVal *T = state->get(Sym)) - if (const ObjCObjectPointerType* PT = + // FIXME: Eventually replace the use of state->get with + // a generic API for reasoning about the Objective-C types of symbolic + // objects. + if (SymbolRef Sym = receiverV.getAsLocSymbol()) + if (const RefVal *T = state->get(Sym)) + if (const ObjCObjectPointerType* PT = T->getType()->getAs()) - ID = PT->getInterfaceDecl(); + ID = PT->getInterfaceDecl(); - // FIXME: this is a hack. This may or may not be the actual method - // that is called. - if (!ID) { - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs()) - ID = PT->getInterfaceDecl(); + // FIXME: this is a hack. This may or may not be the actual method + // that is called. + if (!ID) { + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs()) + ID = PT->getInterfaceDecl(); + } + } else { + // FIXME: Hack for 'super'. + ID = ME->getReceiverInterface(); } - + // FIXME: The receiver could be a reference to a class, meaning that // we should use the class method. RetainSummary *Summ = getInstanceMethodSummary(ME, ID); // Special-case: are we sending a mesage to "self"? // This is a hack. When we have full-IP this should be removed. - if (isa(LC->getDecl())) { + if (isa(LC->getDecl()) && Receiver) { if (const loc::MemRegionVal *L = dyn_cast(&receiverV)) { // Get the region associated with 'self'. if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { @@ -2081,7 +2122,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, // Get the name of the callee (if it is available). SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); if (const FunctionDecl* FD = X.getAsFunctionDecl()) - os << "Call to function '" << FD->getNameAsString() <<'\''; + os << "Call to function '" << FD << '\''; else os << "function call"; } @@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } } else if (const ObjCMessageExpr *ME = dyn_cast(S)) { - if (const Expr *receiver = ME->getReceiver()) + if (const Expr *receiver = ME->getInstanceReceiver()) if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) { // The symbol we are tracking is the receiver. AEffects.push_back(Summ->getReceiverEffect()); @@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this // is a call to a class method whose type we can resolve. In such // cases, promote the return type to XXX* (where XXX is the class). - const ObjCInterfaceDecl *D = ME->getClassInfo().Decl; + const ObjCInterfaceDecl *D = ME->getReceiverInterface(); return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); } @@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, RetEffect RE = Summ.getRetEffect(); if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { - assert(Receiver); - SVal V = state->getSValAsScalarOrLoc(Receiver); bool found = false; - if (SymbolRef Sym = V.getAsLocSymbol()) - if (state->get(Sym)) { - found = true; - RE = Summaries.getObjAllocRetEffect(); - } - + if (Receiver) { + SVal V = state->getSValAsScalarOrLoc(Receiver); + if (SymbolRef Sym = V.getAsLocSymbol()) + if (state->get(Sym)) { + found = true; + RE = Summaries.getObjAllocRetEffect(); + } + } // FIXME: Otherwise, this is a send-to-super instance message. if (!found) RE = RetEffect::MakeNoRet(); } @@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, ExplodedNode* Pred, const GRState *state) { RetainSummary *Summ = - ME->getReceiver() + ME->isInstanceMessage() ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) : Summaries.getClassMethodSummary(ME); assert(Summ && "RetainSummary is null"); - EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL, + EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL, ME->arg_begin(), ME->arg_end(), Pred, state); } diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index dec375e..82e93a4 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -31,6 +31,7 @@ add_clang_library(clangChecker FlatStore.cpp GRBlockCounter.cpp GRCoreEngine.cpp + GRCXXExprEngine.cpp GRExprEngine.cpp GRExprEngineExperimentalChecks.cpp GRState.cpp diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index dd1856c9..c619d75 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -154,8 +154,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, os << "Passed-by-value struct argument contains uninitialized data"; if (F.FieldChain.size() == 1) - os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() - << "')"; + os << " (e.g., field: '" << F.FieldChain[0] << "')"; else { os << " (e.g., via the field chain: '"; bool first = true; @@ -165,7 +164,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, first = false; else os << '.'; - os << (*DI)->getNameAsString(); + os << *DI; } os << "')"; } @@ -219,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, const GRState *state = C.getState(); - if (const Expr *receiver = ME->getReceiver()) + // FIXME: Handle 'super'? + if (const Expr *receiver = ME->getInstanceReceiver()) if (state->getSVal(receiver).isUndef()) { if (ExplodedNode *N = C.GenerateSink()) { if (!BT_msg_undef) @@ -266,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, << 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); + if (const Expr *receiver = ME->getInstanceReceiver()) { + report->addRange(receiver->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + receiver); + } C.EmitReport(report); } @@ -289,7 +290,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, ASTContext &Ctx = C.getASTContext(); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); - if (CanRetTy->isStructureType()) { + if (CanRetTy->isStructureOrClassType()) { // 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. diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp index 2c16f89..eeaed97 100644 --- a/lib/Checker/CastToStructChecker.cpp +++ b/lib/Checker/CastToStructChecker.cpp @@ -51,7 +51,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, QualType OrigPointeeTy = OrigPTy->getPointeeType(); QualType ToPointeeTy = ToPTy->getPointeeType(); - if (!ToPointeeTy->isStructureType()) + if (!ToPointeeTy->isStructureOrClassType()) return; // We allow cast from void*. diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp index d9606f1..c23be87 100644 --- a/lib/Checker/CheckObjCDealloc.cpp +++ b/lib/Checker/CheckObjCDealloc.cpp @@ -27,10 +27,14 @@ using namespace clang; static bool scan_dealloc(Stmt* S, Selector Dealloc) { if (ObjCMessageExpr* ME = dyn_cast(S)) - if (ME->getSelector() == Dealloc) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) - return isa(Receiver); + if (ME->getSelector() == Dealloc) { + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: return false; + case ObjCMessageExpr::SuperInstance: return true; + case ObjCMessageExpr::Class: break; + case ObjCMessageExpr::SuperClass: break; + } + } // Recurse to children. @@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, // [mMyIvar release] if (ObjCMessageExpr* ME = dyn_cast(S)) if (ME->getSelector() == Release) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (ME->getInstanceReceiver()) + if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) if (ObjCIvarRefExpr* E = dyn_cast(Receiver)) if (E->getDecl() == ID) return true; // [self setMyIvar:nil]; if (ObjCMessageExpr* ME = dyn_cast(S)) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (ME->getInstanceReceiver()) + if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) if (DeclRefExpr* E = dyn_cast(Receiver)) if (E->getDecl()->getIdentifier() == SelfII) if (ME->getMethodDecl() == PD->getSetterMethodDecl() && @@ -166,8 +170,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, std::string buf; llvm::raw_string_ostream os(buf); - os << "Objective-C class '" << D->getNameAsString() - << "' lacks a 'dealloc' instance method"; + os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method"; BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; @@ -182,8 +185,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, std::string buf; llvm::raw_string_ostream os(buf); - os << "The 'dealloc' instance method in Objective-C class '" - << D->getNameAsString() + os << "The 'dealloc' instance method in Objective-C class '" << D << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; @@ -238,7 +240,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, ? "missing ivar release (leak)" : "missing ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID->getNameAsString() + os << "The '" << ID << "' instance variable was retained by a synthesized property but " "wasn't released in 'dealloc'"; } else { @@ -246,7 +248,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, ? "extra ivar release (use-after-release)" : "extra ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID->getNameAsString() + os << "The '" << ID << "' instance variable was not retained by a synthesized property " "but was released in 'dealloc'"; } diff --git a/lib/Checker/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp index 8c43a45..76a0923 100644 --- a/lib/Checker/CheckObjCInstMethSignature.cpp +++ b/lib/Checker/CheckObjCInstMethSignature.cpp @@ -49,16 +49,16 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, llvm::raw_string_ostream os(sbuf); os << "The Objective-C class '" - << MethDerived->getClassInterface()->getNameAsString() + << MethDerived->getClassInterface() << "', which is derived from class '" - << MethAncestor->getClassInterface()->getNameAsString() + << MethAncestor->getClassInterface() << "', defines the instance method '" << MethDerived->getSelector().getAsString() << "' whose return type is '" << ResDerived.getAsString() << "'. A method with the same name (same selector) is also defined in " "class '" - << MethAncestor->getClassInterface()->getNameAsString() + << MethAncestor->getClassInterface() << "' and has a return type of '" << ResAncestor.getAsString() << "'. These two types are incompatible, and may result in undefined " diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index efbce61..74e12b1 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -387,11 +387,11 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "'" << FD->getNameAsString() << "' is a poor random number generator"; + os1 << '\'' << FD << "' is a poor random number generator"; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "Function '" << FD->getNameAsString() + os2 << "Function '" << FD << "' is obsolete because it implements a poor random number generator." << " Use 'arc4random' instead"; @@ -472,14 +472,12 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "Return value is not checked in call to '" << FD->getNameAsString() - << "'"; + os1 << "Return value is not checked in call to '" << FD << '\''; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "The return value from the call to '" << FD->getNameAsString() - << "' is not checked. If an error occurs in '" - << FD->getNameAsString() + os2 << "The return value from the call to '" << FD + << "' is not checked. If an error occurs in '" << FD << "', the following code may execute with unexpected privileges"; SourceRange R = CE->getCallee()->getSourceRange(); diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index be1a677..addfc21 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -37,6 +37,13 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { return ValMgr.makeIntVal(C->getValue(), C->getType()); } + case Stmt::CXXBoolLiteralExprClass: { + const SVal *X = ExprBindings.lookup(E); + if (X) + return *X; + else + return ValMgr.makeIntVal(cast(E)); + } case Stmt::IntegerLiteralClass: { // In C++, this expression may have been bound to a temporary object. SVal const *X = ExprBindings.lookup(E); diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp new file mode 100644 index 0000000..00ac995 --- /dev/null +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -0,0 +1,246 @@ +//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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 C++ expression evaluation engine. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; + +void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE, + const FunctionProtoType *FnType, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + llvm::SmallVector WorkList; + WorkList.reserve(AE - AI); + WorkList.push_back(CallExprWLItem(AI, Pred)); + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + Dst.insert(Item.N); + continue; + } + + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AI; + bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType() + : false; + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } +} + +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, + const StackFrameContext *SFC) { + Type *T = D->getParent()->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T,0)); + return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); +} + +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + ValMgr.getRegionManager().getCXXObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + +void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), Dest, Pred, Dst); + return; + } + + const CXXConstructorDecl *CD = E->getConstructor(); + assert(CD); + + if (!CD->isThisDeclarationADefinition()) + // FIXME: invalidate the object. + return; + + + // Evaluate other arguments. + ExplodedNodeSet ArgsEvaluated; + const FunctionProtoType *FnType = CD->getType()->getAs(); + EvalArguments(const_cast(E)->arg_begin(), + const_cast(E)->arg_end(), + FnType, Pred, ArgsEvaluated); + // The callee stack frame context used to create the 'this' parameter region. + const StackFrameContext *SFC = AMgr.getStackFrame(CD, + Pred->getLocationContext(), + E, Builder->getBlock(), Builder->getIndex()); + + const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); + + CallEnter Loc(E, CD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), + NE = ArgsEvaluated.end(); NI != NE; ++NI) { + const GRState *state = GetState(*NI); + // Setup 'this' region. + state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + if (N) + Dst.Add(N); + } +} + +void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the method type. + const FunctionProtoType *FnType = + MCE->getCallee()->getType()->getAs(); + assert(FnType && "Method type not available"); + + // Evaluate explicit arguments with a worklist. + ExplodedNodeSet ArgsEvaluated; + EvalArguments(const_cast(MCE)->arg_begin(), + const_cast(MCE)->arg_end(), + FnType, Pred, ArgsEvaluated); + + // Evaluate the implicit object argument. + ExplodedNodeSet AllArgsEvaluated; + const MemberExpr *ME = dyn_cast(MCE->getCallee()->IgnoreParens()); + if (!ME) + return; + Expr *ObjArgExpr = ME->getBase(); + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + if (ME->isArrow()) + Visit(ObjArgExpr, *I, AllArgsEvaluated); + else + VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); + } + + const CXXMethodDecl *MD = cast(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + + if (!MD->isThisDeclarationADefinition()) + // FIXME: conservative method call evaluation. + return; + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, MD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), + E = AllArgsEvaluated.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); + ExplodedNode *N = Builder->generateNode(Loc, state, *I); + if (N) + Dst.Add(N); + } +} + +void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (CNE->isArray()) { + // FIXME: allocating an array has not been handled. + return; + } + + unsigned Count = Builder->getCurrentBlockCount(); + DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, + CNE->getType(), Count); + const MemRegion *NewReg = cast(SymVal).getRegion(); + + QualType ObjTy = CNE->getType()->getAs()->getPointeeType(); + + const ElementRegion *EleReg = + getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + + // Evaluate constructor arguments. + const FunctionProtoType *FnType = NULL; + const CXXConstructorDecl *CD = CNE->getConstructor(); + if (CD) + FnType = CD->getType()->getAs(); + ExplodedNodeSet ArgsEvaluated; + EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), + FnType, Pred, ArgsEvaluated); + + // Initialize the object region and bind the 'new' expression. + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + if (ObjTy->isRecordType()) { + Store store = state->getStore(); + StoreManager::InvalidatedSymbols IS; + store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS); + state = state->makeWithStore(store); + } else { + if (CNE->hasInitializer()) { + SVal V = state->getSVal(*CNE->constructor_arg_begin()); + state = state->bindLoc(loc::MemRegionVal(EleReg), V); + } else { + // Explicitly set to undefined, because currently we retrieve symbolic + // value from symbolic region. + state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); + } + } + state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); + MakeNode(Dst, CNE, *I, state); + } +} + +void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Should do more checking. + ExplodedNodeSet ArgEvaluated; + Visit(CDE->getArgument(), Pred, ArgEvaluated); + for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(), + E = ArgEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + MakeNode(Dst, CDE, *I, state); + } +} + +void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the this object region from StoreManager. + const MemRegion *R = + ValMgr.getRegionManager().getCXXThisRegion( + getContext().getCanonicalType(TE->getType()), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); +} diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index e4ef6b0..23a87d3 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -455,6 +455,33 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { Eng.WList->Enqueue(Succ, B, Idx+1); } +ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St, + ProgramPoint::Kind K) { + const GRState* PredState = GetState(Pred); + + // If the state hasn't changed, don't generate a new node. + if (!BuildSinks && St == PredState && Auditor == 0) { + Dst.Add(Pred); + return NULL; + } + + ExplodedNode* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else { + if (Auditor && Auditor->Audit(N, Mgr)) + N->markAsSink(); + + Dst.Add(N); + } + } + + return N; +} + static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const void *tag){ switch (K) { diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index bab8922..67090b8 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -584,43 +584,81 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXNamedCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXReinterpretCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::CXXTypeidExprClass: - case Stmt::CXXBoolLiteralExprClass: - case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::CXXThrowExprClass: - case Stmt::CXXDefaultArgExprClass: - case Stmt::CXXZeroInitValueExprClass: - case Stmt::CXXNewExprClass: - case Stmt::CXXDeleteExprClass: - case Stmt::CXXPseudoDestructorExprClass: - case Stmt::UnresolvedLookupExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::DependentScopeDeclRefExprClass: - case Stmt::CXXConstructExprClass: + case Stmt::CXXBindReferenceExprClass: case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXTryStmtClass: + case Stmt::CXXTypeidExprClass: case Stmt::CXXUnresolvedConstructExprClass: - case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXZeroInitValueExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: - case Stmt::CXXCatchStmtClass: - case Stmt::CXXTryStmtClass: { + { SaveAndRestore OldSink(Builder->BuildSinks); Builder->BuildSinks = true; MakeNode(Dst, S, Pred, GetState(Pred)); break; } - default: - // Cases we intentionally have "default" handle: - // AddrLabelExpr, IntegerLiteral, CharacterLiteral + // Cases that should never be evaluated simply because they shouldn't + // appear in the CFG. + case Stmt::BreakStmtClass: + case Stmt::CaseStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::DoStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::LabelStmtClass: + case Stmt::NoStmtClass: + case Stmt::NullStmtClass: + case Stmt::SwitchCaseClass: + llvm_unreachable("Stmt should not be in analyzer evaluation loop"); + break; + // Cases not handled yet; but will handle some day. + case Stmt::DesignatedInitExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::GNUNullExprClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCAtTryStmtClass: + case Stmt::ObjCEncodeExprClass: + case Stmt::ObjCImplicitSetterGetterRefExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::ObjCProtocolExprClass: + case Stmt::ObjCSelectorExprClass: + case Stmt::ObjCStringLiteralClass: + case Stmt::ObjCSuperExprClass: + case Stmt::ParenListExprClass: + case Stmt::PredefinedExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::TypesCompatibleExprClass: + case Stmt::VAArgExprClass: + // Fall through. + + // Cases we intentionally don't evaluate, since they don't need + // to be explicitly evaluated. + case Stmt::AddrLabelExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::FloatingLiteralClass: Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; @@ -678,6 +716,17 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXNewExprClass: { + CXXNewExpr *NE = cast(S); + VisitCXXNewExpr(NE, Pred, Dst); + break; + } + + case Stmt::CXXDeleteExprClass: { + CXXDeleteExpr *CDE = cast(S); + VisitCXXDeleteExpr(CDE, Pred, Dst); + break; + } // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. @@ -720,7 +769,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: { + case Stmt::CStyleCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: { CastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; @@ -769,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitReturnStmt(cast(S), Pred, Dst); break; + case Stmt::OffsetOfExprClass: + VisitOffsetOfExpr(cast(S), Pred, Dst); + break; + case Stmt::SizeOfAlignOfExprClass: VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); break; @@ -935,6 +993,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; // In C++, binding an rvalue to a reference requires to create an object. + case Stmt::CXXBoolLiteralExprClass: case Stmt::IntegerLiteralClass: CreateCXXTemporaryObject(Ex, Pred, Dst); return; @@ -1751,21 +1810,6 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, } } -//===----------------------------------------------------------------------===// -// Transfer function: Function calls. -//===----------------------------------------------------------------------===// - -namespace { -class CallExprWLItem { -public: - CallExpr::arg_iterator I; - ExplodedNode *N; - - CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} -}; -} // end anonymous namespace - void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, @@ -1916,7 +1960,7 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, continue; } - const GRState* state = Pred->getState(); + const GRState* state = GetState(Pred); SVal V = state->getSVal(Ex); if (nonloc::SymExprVal *SEV = dyn_cast(&V)) { // First assume that the condition is true. @@ -2087,7 +2131,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // But first evaluate the receiver (if any). ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); - if (Expr *Receiver = ME->getReceiver()) { + if (Expr *Receiver = ME->getInstanceReceiver()) { ExplodedNodeSet Tmp; Visit(Receiver, Pred, Tmp); @@ -2139,8 +2183,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, SaveAndRestore OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->HasGeneratedNode); - if (const Expr *Receiver = ME->getReceiver()) { - const GRState *state = Pred->getState(); + if (const Expr *Receiver = ME->getInstanceReceiver()) { + const GRState *state = GetState(Pred); // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = @@ -2169,8 +2213,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // Dispatch to plug-in transfer function. EvalObjCMessageExpr(DstEval, ME, Pred, notNilState); } - else { - IdentifierInfo* ClsName = ME->getClassName(); + else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { + IdentifierInfo* ClsName = Iface->getIdentifier(); Selector S = ME->getSelector(); // Check for special instance methods. @@ -2464,9 +2508,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, QualType T = getContext().getCanonicalType(E->getType()); unsigned NumInitElements = E->getNumInits(); - if (T->isArrayType() || T->isStructureType() || - T->isUnionType() || T->isVectorType()) { - + if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { llvm::ImmutableList StartVals = getBasicVals().getEmptySValList(); // Handle base case where the initializer has no elements. @@ -2573,6 +2615,21 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } +void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + Expr::EvalResult Res; + if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); + assert(OOE->getType()->isIntegerType()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); + return; + } + // FIXME: Handle the case where __builtin_offsetof is not a constant. + Dst.Add(Pred); +} void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { @@ -2654,19 +2711,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, case UnaryOperator::OffsetOf: { Expr::EvalResult Res; if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); - assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); - assert(U->getType()->isIntegerType()); - assert(IV.isSigned() == U->getType()->isSignedIntegerType()); - SVal X = ValMgr.makeIntVal(IV); - MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); - return; - } + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); + assert(U->getType()->isIntegerType()); + assert(IV.isSigned() == U->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); + return; + } // FIXME: Handle the case where __builtin_offsetof is not a constant. Dst.Add(Pred); return; } - + case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH. case UnaryOperator::Extension: { @@ -2860,20 +2917,6 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } } - -void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, - ExplodedNodeSet & Dst) { - // Get the this object region from StoreManager. - const MemRegion *R = - ValMgr.getRegionManager().getCXXThisRegion( - getContext().getCanonicalType(TE->getType()), - Pred->getLocationContext()); - - const GRState *state = GetState(Pred); - SVal V = state->getSVal(loc::MemRegionVal(R)); - MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); -} - void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); @@ -3006,7 +3049,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, ExplodedNodeSet Tmp3; for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { - SVal LeftV = (*I1)->getState()->getSVal(LHS); + SVal LeftV = GetState(*I1)->getSVal(LHS); ExplodedNodeSet Tmp2; Visit(RHS, *I1, Tmp2); @@ -3147,184 +3190,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } -void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - const GRState *state = GetState(*I); - - // Bind the temporary object to the value of the expression. Then bind - // the expression to the location of the object. - SVal V = state->getSVal(Ex); - - const MemRegion *R = - ValMgr.getRegionManager().getCXXObjectRegion(Ex, - Pred->getLocationContext()); - - state = state->bindLoc(loc::MemRegionVal(R), V); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); - } -} - -void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (E->isElidable()) { - VisitAggExpr(E->getArg(0), Dest, Pred, Dst); - return; - } - - const CXXConstructorDecl *CD = E->getConstructor(); - assert(CD); - - if (!CD->isThisDeclarationADefinition()) - // FIXME: invalidate the object. - return; - - - // Evaluate other arguments. - CXXConstructExpr::arg_iterator AB - = const_cast(E)->arg_begin(); - CXXConstructExpr::arg_iterator AE - = const_cast(E)->arg_end(); - llvm::SmallVector WorkList; - WorkList.reserve(AE - AB); - WorkList.push_back(CallExprWLItem(AB, Pred)); - ExplodedNodeSet ArgsEvaluated; - const FunctionProtoType *Proto = CD->getType()->getAs(); - - while (!WorkList.empty()) { - CallExprWLItem Item = WorkList.back(); - WorkList.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - // Evaluate the argument. - ExplodedNodeSet Tmp; - const unsigned ParamIdx = Item.I - AB; - - bool VisitAsLvalue = false; - - if (ParamIdx < Proto->getNumArgs()) - VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - - if (VisitAsLvalue) - VisitLValue(*Item.I, Item.N, Tmp); - else - Visit(*Item.I, Item.N, Tmp); - - ++(Item.I); - - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - WorkList.push_back(CallExprWLItem(Item.I, *NI)); - } - // The callee stack frame context used to create the 'this' parameter region. - const StackFrameContext *SFC = AMgr.getStackFrame(CD, - Pred->getLocationContext(), - E, Builder->getBlock(), Builder->getIndex()); - - const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); - - CallEnter Loc(E, CD, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), - NE = ArgsEvaluated.end(); NI != NE; ++NI) { - const GRState *state = GetState(*NI); - // Setup 'this' region. - state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) - Dst.Add(N); - } -} - -void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the method type. - const FunctionProtoType *FnType = - MCE->getCallee()->getType()->getAs(); - assert(FnType && "Method type not available"); - - // Evaluate explicit arguments with a worklist. - CallExpr::arg_iterator AB = const_cast(MCE)->arg_begin(), - AE = const_cast(MCE)->arg_end(); - llvm::SmallVector WorkList; - WorkList.reserve(AE - AB); - WorkList.push_back(CallExprWLItem(AB, Pred)); - ExplodedNodeSet ArgsEvaluated; - - while (!WorkList.empty()) { - CallExprWLItem Item = WorkList.back(); - WorkList.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - ExplodedNodeSet Tmp; - const unsigned ParamIdx = Item.I - AB; - bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType(); - - if (VisitAsLvalue) - VisitLValue(*Item.I, Item.N, Tmp); - else - Visit(*Item.I, Item.N, Tmp); - - ++(Item.I); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) - WorkList.push_back(CallExprWLItem(Item.I, *NI)); - } - // Evaluate the implicit object argument. - ExplodedNodeSet AllArgsEvaluated; - const MemberExpr *ME = dyn_cast(MCE->getCallee()->IgnoreParens()); - if (!ME) - return; - Expr *ObjArgExpr = ME->getBase(); - for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), - E = ArgsEvaluated.end(); I != E; ++I) { - if (ME->isArrow()) - Visit(ObjArgExpr, *I, AllArgsEvaluated); - else - VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); - } - - const CXXMethodDecl *MD = cast(ME->getMemberDecl()); - assert(MD && "not a CXXMethodDecl?"); - - if (!MD->isThisDeclarationADefinition()) - // FIXME: conservative method call evaluation. - return; - - const StackFrameContext *SFC = AMgr.getStackFrame(MD, - Pred->getLocationContext(), - MCE, - Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, MD, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), - E = AllArgsEvaluated.end(); I != E; ++I) { - // Set up 'this' region. - const GRState *state = GetState(*I); - state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); - ExplodedNode *N = Builder->generateNode(Loc, state, *I); - if (N) - Dst.Add(N); - } -} - -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, - const StackFrameContext *SFC) { - Type *T = D->getParent()->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T,0)); - return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); -} - //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9f12ab6..9a664c7 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -365,11 +365,11 @@ void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { } void FieldRegion::dumpToStream(llvm::raw_ostream& os) const { - os << superRegion << "->" << getDecl()->getNameAsString(); + os << superRegion << "->" << getDecl(); } void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}'; + os << "ivar{" << superRegion << ',' << getDecl() << '}'; } void StringRegion::dumpToStream(llvm::raw_ostream& os) const { @@ -381,7 +381,7 @@ void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const { } void VarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << cast(D)->getNameAsString(); + os << cast(D); } void RegionRawOffset::dump() const { @@ -647,13 +647,14 @@ bool MemRegion::hasGlobalsOrParametersStorage() const { const MemRegion *MemRegion::getBaseRegion() const { const MemRegion *R = this; while (true) { - if (const ElementRegion *ER = dyn_cast(R)) { - R = ER->getSuperRegion(); - continue; - } - if (const FieldRegion *FR = dyn_cast(R)) { - R = FR->getSuperRegion(); - continue; + switch (R->getKind()) { + case MemRegion::ElementRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + R = cast(R)->getSuperRegion(); + continue; + default: + break; } break; } diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp index 29bac9c..48f03a3 100644 --- a/lib/Checker/NSAutoreleasePoolChecker.cpp +++ b/lib/Checker/NSAutoreleasePoolChecker.cpp @@ -56,7 +56,7 @@ void NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { - const Expr *receiver = ME->getReceiver(); + const Expr *receiver = ME->getInstanceReceiver(); if (!receiver) return; diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp index 9130bfa..e30d54c 100644 --- a/lib/Checker/NSErrorChecker.cpp +++ b/lib/Checker/NSErrorChecker.cpp @@ -226,7 +226,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param, else os << "documented in CoreFoundation/CFError.h the parameter '"; - os << Param->getNameAsString() << "' may be null."; + os << Param << "' may be null."; BugReport *report = new BugReport(*this, os.str(), *I); // FIXME: Notable symbols are now part of the report. We should diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp index 04d897a..0e47621 100644 --- a/lib/Checker/ObjCUnusedIVarsChecker.cpp +++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp @@ -150,8 +150,7 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (I->second == Unused) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - os << "Instance variable '" << I->first->getNameAsString() - << "' in class '" << ID->getNameAsString() + os << "Instance variable '" << I->first << "' in class '" << ID << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index c97da33..1e15d43 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -14,22 +14,22 @@ // parameters are created lazily. // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Support/Optional.h" -#include "clang/Basic/TargetInfo.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" - -#include "llvm/ADT/ImmutableMap.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/MemRegion.h" #include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using llvm::Optional; //===----------------------------------------------------------------------===// // Representation of binding keys. @@ -346,8 +346,6 @@ public: // Part of public interface to class. Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store, const TypedRegion *R); - const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); - //===------------------------------------------------------------------===// // State pruning. //===------------------------------------------------------------------===// @@ -995,14 +993,6 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { return true; } -const ElementRegion * -RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) { - ASTContext &Ctx = getContext(); - SVal idx = ValMgr.makeZeroArrayIndex(); - assert(!T.isNull()); - return MRMgr.getElementRegion(T, idx, R, Ctx); -} - SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { assert(!isa(L) && "location unknown"); assert(!isa(L) && "location undefined"); @@ -1047,7 +1037,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } #endif - if (RTy->isStructureType() || RTy->isClassType()) + if (RTy->isStructureOrClassType()) return RetrieveStruct(store, R); // FIXME: Handle unions. @@ -1355,7 +1345,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); - assert(T->isStructureType() || T->isClassType()); + assert(T->isStructureOrClassType()); return ValMgr.makeLazyCompoundVal(store, R); } @@ -1385,7 +1375,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) { // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast(R)) - if (TR->getValueType(getContext())->isStructureType()) + if (TR->getValueType(getContext())->isStructureOrClassType()) return BindStruct(store, TR, V); // Special case: the current region represents a cast and it and the super @@ -1439,7 +1429,7 @@ Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR, if (T->isArrayType()) return BindArray(store, VR, InitVal); - if (T->isStructureType()) + if (T->isStructureOrClassType()) return BindStruct(store, VR, InitVal); return Bind(store, ValMgr.makeLoc(VR), InitVal); @@ -1464,7 +1454,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store, V = ValMgr.makeNull(); else if (T->isIntegerType()) V = ValMgr.makeZeroVal(T); - else if (T->isStructureType() || T->isArrayType()) { + else if (T->isStructureOrClassType() || 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); @@ -1540,7 +1530,7 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R, SVal Idx = ValMgr.makeArrayIndex(i); const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); - if (ElementTy->isStructureType()) + if (ElementTy->isStructureOrClassType()) store = BindStruct(store, ER, *VI); else store = Bind(store, ValMgr.makeLoc(ER), *VI); @@ -1561,7 +1551,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, return store; QualType T = R->getValueType(getContext()); - assert(T->isStructureType()); + assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs(); RecordDecl* RD = RT->getDecl(); @@ -1593,7 +1583,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, if (FTy->isArrayType()) store = BindArray(store, FR, *VI); - else if (FTy->isStructureType()) + else if (FTy->isStructureOrClassType()) store = BindStruct(store, FR, *VI); else store = Bind(store, ValMgr.makeLoc(FR), *VI); diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp index 4bfa2cd..d756be7 100644 --- a/lib/Checker/SVals.cpp +++ b/lib/Checker/SVals.cpp @@ -318,7 +318,8 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const { } case nonloc::LazyCompoundValKind: { const nonloc::LazyCompoundVal &C = *cast(this); - os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion() + os << "lazyCompoundVal{" << const_cast(C.getStore()) + << ',' << C.getRegion() << '}'; break; } diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp index fb1d74a..dd38a43 100644 --- a/lib/Checker/SimpleSValuator.cpp +++ b/lib/Checker/SimpleSValuator.cpp @@ -113,16 +113,22 @@ SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) { if (castTy->isUnionType()) return UnknownVal(); - assert(castTy->isIntegerType()); - unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); + if (castTy->isIntegerType()) { + unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); - if (!isa(val)) - return ValMgr.makeLocAsInteger(val, BitWidth); + if (!isa(val)) + return ValMgr.makeLocAsInteger(val, BitWidth); - llvm::APSInt i = cast(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); - i.extOrTrunc(BitWidth); - return ValMgr.makeIntVal(i); + llvm::APSInt i = cast(val).getValue(); + i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); + i.extOrTrunc(BitWidth); + return ValMgr.makeIntVal(i); + } + + // All other cases: return 'UnknownVal'. This includes casting pointers + // to floats, which is probably badness it itself, but this is a good + // intermediate solution until we do something better. + return UnknownVal(); } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp index e524cb3..c12065b 100644 --- a/lib/Checker/Store.cpp +++ b/lib/Checker/Store.cpp @@ -38,6 +38,13 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { return true; } +const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R, + QualType T) { + SVal idx = ValMgr.makeZeroArrayIndex(); + assert(!T.isNull()); + return MRMgr.getElementRegion(T, idx, R, Ctx); +} + const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) { ASTContext& Ctx = StateMgr.getContext(); @@ -170,13 +177,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (IsCompleteType(Ctx, PointeeTy)) { // Compute the size in **bytes**. CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy); - - // Is the offset a multiple of the size? If so, we can layer the - // ElementRegion (with elementType == PointeeTy) directly on top of - // the base region. - if (off % pointeeTySize == 0) { - newIndex = off / pointeeTySize; - newSuperR = baseR; + if (!pointeeTySize.isZero()) { + // Is the offset a multiple of the size? If so, we can layer the + // ElementRegion (with elementType == PointeeTy) directly on top of + // the base region. + if (off % pointeeTySize == 0) { + newIndex = off / pointeeTySize; + newSuperR = baseR; + } } } diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp index d75e5d2..e9b8f09 100644 --- a/lib/Checker/UnixAPIChecker.cpp +++ b/lib/Checker/UnixAPIChecker.cpp @@ -13,23 +13,30 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include using namespace clang; +using llvm::Optional; namespace { class UnixAPIChecker : public CheckerVisitor { enum SubChecks { OpenFn = 0, + PthreadOnceFn = 1, NumChecks }; BugType *BTypes[NumChecks]; public: + Optional Val_O_CREAT; + +public: UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } static void *getTag() { static unsigned tag = 0; return &tag; } @@ -55,7 +62,21 @@ static inline void LazyInitialize(BugType *&BT, const char *name) { // "open" (man 2 open) //===----------------------------------------------------------------------===// -static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { +static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC, + const CallExpr *CE, BugType *&BT) { + // The definition of O_CREAT is platform specific. We need a better way + // of querying this information from the checking environment. + if (!UC.Val_O_CREAT.hasValue()) { + if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple) + UC.Val_O_CREAT = 0x0200; + else { + // FIXME: We need a more general way of getting the O_CREAT value. + // We could possibly grovel through the preprocessor state, but + // that would require passing the Preprocessor object to the GRExprEngine. + return; + } + } + LazyInitialize(BT, "Improper use of 'open'"); // Look at the 'oflags' argument for the O_CREAT flag. @@ -77,7 +98,7 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { } NonLoc oflags = cast(V); NonLoc ocreateFlag = - cast(C.getValueManager().makeIntVal((uint64_t) O_CREAT, + cast(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(), oflagsEx->getType())); SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And, oflags, ocreateFlag, @@ -110,21 +131,67 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { } //===----------------------------------------------------------------------===// +// pthread_once +//===----------------------------------------------------------------------===// + +static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &, + const CallExpr *CE, BugType *&BT) { + + // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. + // They can possibly be refactored. + + LazyInitialize(BT, "Improper use of 'pthread_once'"); + + if (CE->getNumArgs() < 1) + return; + + // Check if the first argument is stack allocated. If so, issue a warning + // because that's likely to be bad news. + const GRState *state = C.getState(); + const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); + if (!R || !isa(R->getMemorySpace())) + return; + + ExplodedNode *N = C.GenerateSink(state); + if (!N) + return; + + llvm::SmallString<256> S; + llvm::raw_svector_ostream os(S); + os << "Call to 'pthread_once' uses"; + if (const VarRegion *VR = dyn_cast(R)) + os << " the local variable '" << VR->getDecl()->getName() << '\''; + else + os << " stack allocated memory"; + os << " for the \"control\" value. Using such transient memory for " + "the control value is potentially dangerous."; + if (isa(R) && isa(R->getMemorySpace())) + os << " Perhaps you intended to declare the variable as 'static'?"; + + EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// // Central dispatch function. //===----------------------------------------------------------------------===// -typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT); +typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC, + const CallExpr *CE, BugType *&BT); namespace { class SubCheck { SubChecker SC; + UnixAPIChecker *UC; BugType **BT; public: - SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} - SubCheck() : SC(NULL), BT(NULL) {} + SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc), + BT(&bt) {} + SubCheck() : SC(NULL), UC(NULL), BT(NULL) {} void run(CheckerContext &C, const CallExpr *CE) const { if (SC) - SC(C, CE, *BT); + SC(C, *UC, CE, *BT); } }; } // end anonymous namespace @@ -146,7 +213,9 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const SubCheck &SC = llvm::StringSwitch(FI->getName()) - .Case("open", SubCheck(CheckOpen, BTypes[OpenFn])) + .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn])) + .Case("pthread_once", SubCheck(CheckPthreadOnce, this, + BTypes[PthreadOnceFn])) .Default(SubCheck()); SC.run(C, CE); diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 5097341..db24def 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -706,7 +706,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, BlockDeclRefDecls); // FIXME: This leaks ImplicitParamDecl *SelfDecl = - ImplicitParamDecl::Create(getContext(), 0, + ImplicitParamDecl::Create(getContext(), const_cast(BD), SourceLocation(), II, ParmTy); @@ -812,7 +812,8 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { Pad.getQuantity()), ArrayType::Normal, 0); ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), - 0, QualType(PadTy), 0, VarDecl::None); + 0, QualType(PadTy), 0, + VarDecl::None, VarDecl::None); Expr *E; E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), SourceLocation()); @@ -860,7 +861,9 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -941,8 +944,9 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); if (NoteForHelperp) { @@ -1025,8 +1029,9 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); // dst->x @@ -1089,8 +1094,9 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); llvm::Value *V = CGF.GetAddrOfLocalVar(Src); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index efee0e3..5646d00 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -38,6 +38,7 @@ namespace llvm { class GlobalValue; class TargetData; class FunctionType; + class PointerType; class Value; class LLVMContext; } @@ -127,7 +128,7 @@ protected: llvm::LLVMContext &VMContext; public: - const llvm::Type *PtrToInt8Ty; + const llvm::PointerType *PtrToInt8Ty; struct HelperInfo { int index; int flag; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 38c40ed..95c41db 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -682,13 +682,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BIsqrt: case Builtin::BIsqrtf: case Builtin::BIsqrtl: { - // Rewrite sqrt to intrinsic if allowed. - if (!FD->hasAttr()) - break; - Value *Arg0 = EmitScalarExpr(E->getArg(0)); - const llvm::Type *ArgType = Arg0->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1); - return RValue::get(Builder.CreateCall(F, Arg0, "tmp")); + // TODO: there is currently no set of optimizer flags + // sufficient for us to rewrite sqrt to @llvm.sqrt. + // -fmath-errno=0 is not good enough; we need finiteness. + // We could probably precondition the call with an ult + // against 0, but is that worth the complexity? + break; } case Builtin::BIpow: @@ -983,8 +982,38 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateStore(Ops[1], Ops[0]); } case X86::BI__builtin_ia32_palignr: { - Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); + unsigned shiftVal = cast(Ops[2])->getZExtValue(); + + // If palignr is shifting the pair of input vectors less than 9 bytes, + // emit a shuffle instruction. + if (shiftVal <= 8) { + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + llvm::SmallVector Indices; + for (unsigned i = 0; i != 8; ++i) + Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i)); + + Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); + return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); + } + + // If palignr is shifting the pair of input vectors more than 8 but less + // than 16 bytes, emit a logical right shift of the destination. + if (shiftVal < 16) { + // MMX has these as 1 x i64 vectors for some odd optimization reasons. + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); + const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 1); + + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); + Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8); + + // create i32 constant + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr"); + } + + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + return llvm::Constant::getNullValue(ConvertType(E->getType())); } case X86::BI__builtin_ia32_palignr128: { unsigned shiftVal = cast(Ops[2])->getZExtValue(); @@ -1025,5 +1054,49 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + llvm::SmallVector Ops; + + for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); + + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + default: return 0; + + // vec_st + case PPC::BI__builtin_altivec_stvx: + case PPC::BI__builtin_altivec_stvxl: + case PPC::BI__builtin_altivec_stvebx: + case PPC::BI__builtin_altivec_stvehx: + case PPC::BI__builtin_altivec_stvewx: + { + Ops[2] = Builder.CreateBitCast(Ops[2], llvm::Type::getInt8PtrTy(VMContext)); + Ops[1] = !isa(Ops[1]) || !cast(Ops[1])->isNullValue() + ? Builder.CreateGEP(Ops[2], Ops[1], "tmp") : Ops[2]; + Ops.pop_back(); + + switch (BuiltinID) { + default: assert(0 && "Unsupported vavg intrinsic!"); + case PPC::BI__builtin_altivec_stvx: + ID = Intrinsic::ppc_altivec_stvx; + break; + case PPC::BI__builtin_altivec_stvxl: + ID = Intrinsic::ppc_altivec_stvxl; + break; + case PPC::BI__builtin_altivec_stvebx: + ID = Intrinsic::ppc_altivec_stvebx; + break; + case PPC::BI__builtin_altivec_stvehx: + ID = Intrinsic::ppc_altivec_stvehx; + break; + case PPC::BI__builtin_altivec_stvewx: + ID = Intrinsic::ppc_altivec_stvewx; + break; + } + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), ""); + } + } return 0; } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 93a182f..74cf113 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -297,15 +297,15 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name, getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer()); } -static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, +static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); - llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty); - Vtable = CGF.Builder.CreateLoad(Vtable); + llvm::Value *VTable = CGF.Builder.CreateBitCast(This, Ty); + VTable = CGF.Builder.CreateLoad(VTable); llvm::Value *VFuncPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn"); + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); return CGF.Builder.CreateLoad(VFuncPtr); } @@ -313,7 +313,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD); + uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } @@ -323,7 +323,7 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *&This, const llvm::Type *Ty) { DD = cast(DD->getCanonicalDecl()); uint64_t VTableIndex = - CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type)); + CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type)); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index cb1ecc1..92d15d9 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -528,7 +528,7 @@ static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) { } const llvm::Type * -CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) { +CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) { const FunctionProtoType *FPT = MD->getType()->getAs(); if (!HasIncompleteReturnTypeOrArgumentTypes(FPT)) @@ -586,8 +586,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, case ABIArgInfo::Indirect: PAL.push_back(llvm::AttributeWithIndex::get(Index, - llvm::Attribute::StructRet | - llvm::Attribute::NoAlias)); + llvm::Attribute::StructRet)); ++Index; // sret disables readnone and readonly FuncAttrs &= ~(llvm::Attribute::ReadOnly | @@ -870,7 +869,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &CallArgs, - const Decl *TargetDecl) { + const Decl *TargetDecl, + llvm::Instruction **callOrInvoke) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. llvm::SmallVector Args; @@ -996,6 +996,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Args.data(), Args.data()+Args.size()); EmitBlock(Cont); } + if (callOrInvoke) { + *callOrInvoke = CS.getInstruction(); + } CS.setAttributes(Attrs); CS.setCallingConv(static_cast(CallingConv)); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 177e862..a604eef 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -20,65 +20,61 @@ using namespace clang; using namespace CodeGen; static uint64_t -ComputeNonVirtualBaseClassOffset(ASTContext &Context, - const CXXBasePath &Path, - unsigned Start) { +ComputeNonVirtualBaseClassOffset(ASTContext &Context, + const CXXRecordDecl *DerivedClass, + CXXBaseSpecifierArray::iterator Start, + CXXBaseSpecifierArray::iterator End) { uint64_t Offset = 0; - - for (unsigned i = Start, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; + + const CXXRecordDecl *RD = DerivedClass; + + for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) { + const CXXBaseSpecifier *Base = *I; + assert(!Base->isVirtual() && "Should not see virtual bases here!"); // Get the layout. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXBaseSpecifier *BS = Element.Base; - assert(!BS->isVirtual() && "Should not see virtual bases here!"); - - const CXXRecordDecl *Base = - cast(BS->getType()->getAs()->getDecl()); + const CXXRecordDecl *BaseDecl = + cast(Base->getType()->getAs()->getDecl()); // Add the offset. - Offset += Layout.getBaseClassOffset(Base) / 8; + Offset += Layout.getBaseClassOffset(BaseDecl); + + RD = BaseDecl; } - - return Offset; + + // FIXME: We should not use / 8 here. + return Offset / 8; } llvm::Constant * -CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass) { - if (Class == BaseClass) - return 0; - - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast(Class)-> - isDerivedFrom(const_cast(BaseClass), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } +CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, + const CXXBaseSpecifierArray &BasePath) { + assert(!BasePath.empty() && "Base path should not be empty!"); - uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), - Paths.front(), 0); + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, + BasePath.begin(), BasePath.end()); if (!Offset) return 0; - + const llvm::Type *PtrDiffTy = - Types.ConvertType(getContext().getPointerDiffType()); - + Types.ConvertType(getContext().getPointerDiffType()); + return llvm::ConstantInt::get(PtrDiffTy, Offset); } -/// Gets the address of a virtual base class within a complete object. +/// Gets the address of a direct base class within a complete object. /// This should only be used for (1) non-virtual bases or (2) virtual bases /// when the type is known to be complete (e.g. in complete destructors). /// /// The object pointed to by 'This' is assumed to be non-null. llvm::Value * -CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, - bool isBaseVirtual, - const CXXRecordDecl *Derived, - const CXXRecordDecl *Base) { +CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base, + bool BaseIsVirtual) { // 'this' must be a pointer (in some address space) to Derived. assert(This->getType()->isPointerTy() && cast(This->getType())->getElementType() @@ -87,7 +83,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, // Compute the offset of the virtual base. uint64_t Offset; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); - if (isBaseVirtual) + if (BaseIsVirtual) Offset = Layout.getVBaseClassOffset(Base); else Offset = Layout.getBaseClassOffset(Base); @@ -105,51 +101,63 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, return V; } -llvm::Value * -CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass, - bool NullCheckValue) { - QualType BTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(BaseClass)); - const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); - - if (Class == BaseClass) { - // Just cast back. - return Builder.CreateBitCast(Value, BasePtrTy); - } +static llvm::Value * +ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, + uint64_t NonVirtual, llvm::Value *Virtual) { + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + llvm::Value *NonVirtualOffset = 0; + if (NonVirtual) + NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual); + + llvm::Value *BaseOffset; + if (Virtual) { + if (NonVirtualOffset) + BaseOffset = CGF.Builder.CreateAdd(Virtual, NonVirtualOffset); + else + BaseOffset = Virtual; + } else + BaseOffset = NonVirtualOffset; + + // Apply the base offset. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); + ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr"); - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast(Class)-> - isDerivedFrom(const_cast(BaseClass), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } + return ThisPtr; +} - unsigned Start = 0; - llvm::Value *VirtualOffset = 0; +llvm::Value * +CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, + bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); - const CXXBasePath &Path = Paths.front(); + CXXBaseSpecifierArray::iterator Start = BasePath.begin(); 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(VBaseType->getAs()->getDecl()); - } + + // Get the virtual base. + if ((*Start)->isVirtual()) { + VBase = + cast((*Start)->getType()->getAs()->getDecl()); + ++Start; } + + uint64_t NonVirtualOffset = + ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived, + Start, BasePath.end()); - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start); + // Get the base pointer type. + const llvm::Type *BasePtrTy = + ConvertType((BasePath.end()[-1])->getType())->getPointerTo(); - if (!Offset && !VBase) { + if (!NonVirtualOffset && !VBase) { // Just cast back. return Builder.CreateBitCast(Value, BasePtrTy); } - + llvm::BasicBlock *CastNull = 0; llvm::BasicBlock *CastNotNull = 0; llvm::BasicBlock *CastEnd = 0; @@ -165,28 +173,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } - + + llvm::Value *VirtualOffset = 0; + if (VBase) - VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase); + VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase); - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - llvm::Value *NonVirtualOffset = 0; - if (Offset) - NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - - llvm::Value *BaseOffset; - if (VBase) { - if (NonVirtualOffset) - BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset); - else - BaseOffset = VirtualOffset; - } else - BaseOffset = NonVirtualOffset; - - // Apply the base offset. - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - Value = Builder.CreateBitCast(Value, Int8PtrTy); - Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr"); + // Apply the offsets. + Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, + VirtualOffset); // Cast back. Value = Builder.CreateBitCast(Value, BasePtrTy); @@ -210,21 +205,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, llvm::Value * CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *Class, - const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); + QualType DerivedTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast(DerivedClass))); + getContext().getCanonicalType(getContext().getTagDeclType(Derived)); const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); - if (Class == DerivedClass) { - // Just cast back. - return Builder.CreateBitCast(Value, DerivedPtrTy); - } - llvm::Value *NonVirtualOffset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class); + CGM.GetNonVirtualBaseClassOffset(Derived, BasePath); if (!NonVirtualOffset) { // No offset, we can just cast back. @@ -274,23 +265,16 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, /// EmitCopyCtorCall - Emit a call to a copy constructor. static void -EmitCopyCtorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType, - llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) { - llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType); +EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor, + llvm::Value *ThisPtr, llvm::Value *Src) { + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete); CallArgList CallArgs; // Push the this ptr. CallArgs.push_back(std::make_pair(RValue::get(ThisPtr), CopyCtor->getThisType(CGF.getContext()))); - - // Push the VTT parameter if necessary. - if (VTT) { - QualType T = CGF.getContext().getPointerType(CGF.getContext().VoidPtrTy); - CallArgs.push_back(std::make_pair(RValue::get(VTT), T)); - } - + // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); @@ -325,13 +309,8 @@ EmitCopyCtorCall(CodeGenFunction &CGF, // FIXME. Consolidate this with EmitCXXAggrConstructorCall. void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast(Array); - assert(CA && "VLA cannot be copied over"); - bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); - + const ConstantArrayType *Array, + const CXXRecordDecl *ClassDecl) { // Create a temporary for the loop index and initialize it with 0. llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), "loop.index"); @@ -347,7 +326,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::BasicBlock *ForBody = createBasicBlock("for.body"); // Generate: if (loop-index < number-of-elements fall to the loop body, // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + uint64_t NumElements = getContext().getConstantArrayElementCount(Array); llvm::Value * NumElementsPtr = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); llvm::Value *Counter = Builder.CreateLoad(IndexPtr); @@ -362,95 +341,8 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, Counter = Builder.CreateLoad(IndexPtr); Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - if (BitwiseCopy) - EmitAggregateCopy(Dest, Src, Ty); - else if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) - EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src); - - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// EmitClassAggrCopyAssignment - This routine generates code to assign a class -/// array of objects from SrcValue to DestValue. Assignment can be either a -/// bitwise assignment or via a copy assignment operator function call. -/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy -void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, - llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast(Array); - assert(CA && "VLA cannot be asssigned"); - bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - 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"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); - llvm::Value * NumElementsPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, - "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the assignment operator call on array element. - Counter = Builder.CreateLoad(IndexPtr); - Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); - Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - const CXXMethodDecl *MD = 0; - if (BitwiseAssign) - EmitAggregateCopy(Dest, Src, Ty); - else { - BaseClassDecl->hasConstCopyAssignment(getContext(), MD); - assert(MD && "EmitClassAggrCopyAssignment - No user assign"); - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - QualType SrcTy = MD->getParamDecl(0)->getType(); - RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : - RValue::getAggregate(Src); - CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, MD); - } + EmitClassMemberwiseCopy(Dest, Src, ClassDecl); + EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -468,7 +360,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, /// GetVTTParameter - Return the VTT parameter that should be passed to a /// base constructor/destructor with virtual bases. -static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { +static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, + bool ForVirtualBase) { if (!CodeGenVTables::needsVTTParameter(GD)) { // This constructor/destructor does not need a VTT parameter. return 0; @@ -486,9 +379,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { if (RD == Base) { assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) && "doing no-op VTT offset in base dtor/ctor?"); + assert(!ForVirtualBase && "Can't have same class as virtual base!"); SubVTTIndex = 0; } else { - SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base); + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = ForVirtualBase ? + Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base); + + SubVTTIndex = + CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); } @@ -511,75 +411,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { /// or via a copy constructor call. void CodeGenFunction::EmitClassMemberwiseCopy( llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, QualType Ty) { - CXXCtorType CtorType = Ctor_Complete; - - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - - // We want to call the base constructor. - CtorType = Ctor_Base; - } - if (BaseClassDecl->hasTrivialCopyConstructor()) { - EmitAggregateCopy(Dest, Src, Ty); + const CXXRecordDecl *ClassDecl) { + if (ClassDecl->hasTrivialCopyConstructor()) { + EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl)); return; } - CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0); - if (!BaseCopyCtor) - return; + CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0); + assert(CopyCtor && "Did not have copy ctor!"); - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType)); - EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src); -} - -/// EmitClassCopyAssignment - This routine generates code to copy assign a class -/// object from SrcValue to DestValue. Assignment can be either a bitwise -/// assignment of via an assignment operator call. -// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. -void CodeGenFunction::EmitClassCopyAssignment( - llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - } - if (BaseClassDecl->hasTrivialCopyAssignment()) { - EmitAggregateCopy(Dest, Src, Ty); - return; - } - - const CXXMethodDecl *MD = 0; - BaseClassDecl->hasConstCopyAssignment(getContext(), MD); - assert(MD && "EmitClassCopyAssignment - missing copy assign"); - - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - QualType SrcTy = MD->getParamDecl(0)->getType(); - RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : - RValue::getAggregate(Src); - CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, MD); + EmitCopyCtorCall(*this, CopyCtor, Dest, Src); } /// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a @@ -600,30 +441,25 @@ void CodeGenFunction::EmitClassCopyAssignment( void CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { const CXXConstructorDecl *Ctor = cast(CurGD.getDecl()); + CXXCtorType CtorType = CurGD.getCtorType(); + (void) CtorType; + const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "SynthesizeCXXCopyConstructor - copy constructor has definition already"); assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy constrution of virtual base NYI - if (Base->isVirtual()) - continue; + llvm::Value *ThisPtr = LoadCXXThis(); - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } + // Find the source pointer. + unsigned SrcArgIndex = Args.size() - 1; + assert(CtorType == Ctor_Base || SrcArgIndex == 1); + assert(CtorType != Ctor_Base || + (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) || + SrcArgIndex == 1); + + llvm::Value *SrcPtr = + Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first)); for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { @@ -638,27 +474,26 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { if (const RecordType *FieldClassType = FieldType->getAs()) { CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0); + LValue LHS = EmitLValueForField(ThisPtr, Field, 0); + LValue RHS = EmitLValueForField(SrcPtr, Field, 0); if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); + const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo(); llvm::Value *DestBaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(), BasePtr); llvm::Value *SrcBaseAddrPtr = Builder.CreateBitCast(RHS.getAddress(), BasePtr); EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); + FieldClassDecl); } else EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); + FieldClassDecl); continue; } // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0); - LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0); + LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0); + LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0); if (!hasAggregateLLVMType(Field->getType())) { RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); @@ -675,100 +510,6 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { InitializeVTablePointers(ClassDecl); } -/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. -/// Before the implicitly-declared copy assignment operator for a class is -/// implicitly defined, all implicitly- declared copy assignment operators for -/// its direct base classes and its nonstatic data members shall have been -/// implicitly defined. [12.8-p12] -/// The implicitly-defined copy assignment operator for class X performs -/// memberwise assignment of its subob- jects. The direct base classes of X are -/// assigned first, in the order of their declaration in -/// the base-specifier-list, and then the immediate nonstatic data members of X -/// are assigned, in the order in which they were declared in the class -/// definition.Each subobject is assigned in the manner appropriate to its type: -/// if the subobject is of class type, the copy assignment operator for the -/// class is used (as if by explicit qualification; that is, ignoring any -/// possible virtual overriding functions in more derived classes); -/// -/// if the subobject is an array, each element is assigned, in the manner -/// appropriate to the element type; -/// -/// if the subobject is of scalar type, the built-in assignment operator is -/// used. -void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) { - const CXXMethodDecl *CD = cast(CurGD.getDecl()); - const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); - assert(!ClassDecl->hasUserDeclaredCopyAssignment() && - "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); - - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy assignment of virtual base NYI - if (Base->isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - if (const RecordType *FieldClassType = FieldType->getAs()) { - CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *DestBaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - llvm::Value *SrcBaseAddrPtr = - Builder.CreateBitCast(RHS.getAddress(), BasePtr); - EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); - } - else - EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); - continue; - } - // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); - if (!hasAggregateLLVMType(Field->getType())) { - RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); - EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); - } else if (Field->getType()->isAnyComplexType()) { - ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), - RHS.isVolatileQualified()); - StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); - } else { - EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); - } - } - - // return *this; - Builder.CreateStore(LoadOfThis, ReturnValue); -} - static void EmitBaseInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXBaseOrMemberInitializer *BaseInit, @@ -782,15 +523,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CXXRecordDecl *BaseClassDecl = cast(BaseType->getAs()->getDecl()); - // FIXME: This method of determining whether a base is virtual is ridiculous; - // it should be part of BaseInit. - bool isBaseVirtual = false; - for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); I != E; ++I) - if (I->getType()->getAs()->getDecl() == BaseClassDecl) { - isBaseVirtual = true; - break; - } + bool isBaseVirtual = BaseInit->isBaseVirtual(); // The base constructor doesn't construct virtual bases. if (CtorType == Ctor_Base && isBaseVirtual) @@ -798,9 +531,10 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, // We can pretend to be a complete class because it only matters for // virtual bases, and we only do virtual bases for complete ctors. - llvm::Value *V = ThisPtr; - V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual, - ClassDecl, BaseClassDecl); + llvm::Value *V = + CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl, + BaseClassDecl, + BaseInit->isBaseVirtual()); CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); @@ -809,7 +543,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CodeGenFunction::EHCleanupBlock Cleanup(CGF); CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext()); - CGF.EmitCXXDestructorCall(DD, Dtor_Base, V); + CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V); } } @@ -850,7 +584,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LHS.isVolatileQualified()); } else { CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), - LHS.isVolatileQualified(), false, true); + LHS.isVolatileQualified(), + /*IgnoreResult*/ false, + /*IsInitializer*/ true); if (!CGF.Exceptions) return; @@ -868,7 +604,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext()); - CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress()); + CGF.EmitCXXDestructorCall(DD, Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); } } } @@ -976,8 +713,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, llvm::SmallVector MemberInitializers; - // FIXME: Add vbase initialization - for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); B != E; ++B) { @@ -1028,7 +763,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // variant, then call the appropriate operator delete() on the way // out. if (DtorType == Dtor_Deleting) { - EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis()); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + LoadCXXThis()); SkipBody = true; // If this is the complete variant, just invoke the base variant; @@ -1036,7 +772,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // this optimization if the body is a function-try-block, because // we'd introduce *two* handler blocks. } else if (!isTryBody && DtorType == Dtor_Complete) { - EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis()); + EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, + LoadCXXThis()); SkipBody = true; // Otherwise, we're in the base variant, so we need to ensure the @@ -1117,11 +854,11 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, if (BaseClassDecl->hasTrivialDestructor()) continue; const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), - true, - ClassDecl, - BaseClassDecl); - EmitCXXDestructorCall(D, Dtor_Base, V); + llvm::Value *V = + GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*BaseIsVirtual=*/true); + EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/true, V); } return; } @@ -1175,7 +912,8 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, Array, BaseAddrPtr); } else EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), - Dtor_Complete, LHS.getAddress()); + Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); } // Destroy non-virtual bases. @@ -1193,12 +931,14 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, // 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); + + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + llvm::Value *V = + GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), ClassDecl, + BaseClassDecl, + /*BaseIsVirtual=*/false); + + EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/false, V); } } @@ -1271,7 +1011,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, { CXXTemporariesCleanupScope Scope(*this); - EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address, + ArgBeg, ArgEnd); } EmitBlock(ContinueBlock); @@ -1345,7 +1086,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); Counter = Builder.CreateSub(Counter, One); llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); - EmitCXXDestructorCall(D, Dtor_Complete, Address); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Address); EmitBlock(ContinueBlock); @@ -1390,6 +1131,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, FunctionDecl::Static, + FunctionDecl::None, false, true); StartFunction(FD, R, Fn, Args, SourceLocation()); QualType BaseElementTy = getContext().getBaseElementType(Array); @@ -1407,7 +1149,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, + CXXCtorType Type, bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { @@ -1429,7 +1171,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, return; } - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type)); + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); @@ -1450,7 +1192,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ++I; // vtt - if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) { + if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType), + /*ForVirtualBase=*/false)) { QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); @@ -1502,8 +1245,10 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, + bool ForVirtualBase, llvm::Value *This) { - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type)); + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), + ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); @@ -1538,7 +1283,8 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, void CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, - bool BaseIsMorallyVirtual, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass) { const CXXRecordDecl *RD = Base.getBase(); @@ -1548,7 +1294,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, // Check if we need to use a vtable from the VTT. if (CodeGenVTables::needsVTTParameter(CurGD) && - (RD->getNumVBases() || BaseIsMorallyVirtual)) { + (RD->getNumVBases() || NearestVBase)) { // Get the secondary vpointer index. uint64_t VirtualPointerIndex = CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base); @@ -1567,20 +1313,27 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, } // Compute where to store the address point. - llvm::Value *VTableField; + llvm::Value *VirtualOffset = 0; + uint64_t NonVirtualOffset = 0; - if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) { + if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) { // We need to use the virtual base offset offset because the virtual base // might have a different offset in the most derived class. - VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD, - /*NullCheckValue=*/false); + VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass, + NearestVBase); + NonVirtualOffset = OffsetFromNearestVBase / 8; } else { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy); - VTableField = - Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8); + // We can just use the base offset in the complete class. + NonVirtualOffset = Base.getBaseOffset() / 8; } + + // Apply the offsets. + llvm::Value *VTableField = LoadCXXThis(); + + if (NonVirtualOffset || VirtualOffset) + VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField, + NonVirtualOffset, + VirtualOffset); // Finally, store the address point. const llvm::Type *AddressPointPtrTy = @@ -1591,7 +1344,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, void CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, - bool BaseIsMorallyVirtual, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -1600,7 +1354,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, // been set. if (!BaseIsNonVirtualPrimaryBase) { // Initialize the vtable pointer for this base. - InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass); + InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase, + VTable, VTableClass); } const CXXRecordDecl *RD = Base.getBase(); @@ -1616,7 +1371,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, continue; uint64_t BaseOffset; - bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + uint64_t BaseOffsetFromNearestVBase; bool BaseDeclIsNonVirtualPrimaryBase; if (I->isVirtual()) { @@ -1628,17 +1383,20 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, getContext().getASTRecordLayout(VTableClass); BaseOffset = Layout.getVBaseClassOffset(BaseDecl); - BaseDeclIsMorallyVirtual = true; + BaseOffsetFromNearestVBase = 0; BaseDeclIsNonVirtualPrimaryBase = false; } else { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); + BaseOffsetFromNearestVBase = + OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl); BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl; } InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset), - BaseDeclIsMorallyVirtual, + I->isVirtual() ? BaseDecl : NearestVBase, + BaseOffsetFromNearestVBase, BaseDeclIsNonVirtualPrimaryBase, VTable, VTableClass, VBases); } @@ -1654,8 +1412,8 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { // Initialize the vtable pointers for this class and all of its bases. VisitedVirtualBasesSetTy VBases; - InitializeVTablePointers(BaseSubobject(RD, 0), - /*BaseIsMorallyVirtual=*/false, + InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0, + /*OffsetFromNearestVBase=*/0, /*BaseIsNonVirtualPrimaryBase=*/false, VTable, RD, VBases); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index bcbda8a..4963e73 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -320,27 +320,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldOffset = 0; FType = CGM.getContext().UnsignedLongTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "reserved", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); + EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); - FieldOffset += FieldSize; - FType = CGM.getContext().UnsignedLongTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "Size", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); EltTys.clear(); @@ -360,49 +342,13 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__reserved", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__FuncPtr", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); - FieldOffset += FieldSize; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = DescTy; FieldSize = CGM.getContext().getTypeSize(Ty); @@ -525,13 +471,20 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, uint64_t FieldOffset = RL.getFieldOffset(FieldNo); + unsigned Flags = 0; + AccessSpecifier Access = I->getAccess(); + if (Access == clang::AS_private) + Flags |= llvm::DIType::FlagPrivate; + else if (Access == clang::AS_protected) + Flags |= llvm::DIType::FlagProtected; + // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); + FieldOffset, Flags, FieldTy); EltTys.push_back(FieldTy); } } @@ -626,7 +579,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. if (!isa(Method)) - VIndex = CGM.getVTables().getMethodVtableIndex(Method); + VIndex = CGM.getVTables().getMethodVTableIndex(Method); ContainingType = RecordTy; } @@ -734,8 +687,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { return VTablePtrType; } -/// getVtableName - Get vtable name for the given Class. -llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { +/// getVTableName - Get vtable name for the given Class. +llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Otherwise construct gdb compatible name name. std::string Name = "_vptr$" + RD->getNameAsString(); @@ -746,10 +699,10 @@ llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { } -/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate +/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate /// debug info entry in EltTys vector. void CGDebugInfo:: -CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, +CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, llvm::SmallVectorImpl &EltTys) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -764,7 +717,7 @@ CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); llvm::DIType VPTR = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - getVtableName(RD), Unit, + getVTableName(RD), Unit, 0, Size, 0, 0, 0, getOrCreateVTablePtrType(Unit)); EltTys.push_back(VPTR); @@ -832,7 +785,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, const CXXRecordDecl *CXXDecl = dyn_cast(RD); if (CXXDecl) { CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl); - CollectVtableInfo(CXXDecl, Unit, EltTys); + CollectVTableInfo(CXXDecl, Unit, EltTys); } CollectRecordFields(RD, Unit, EltTys); llvm::MDNode *ContainingType = NULL; @@ -1293,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast(Ty), Unit); - case Type::InjectedClassName: case Type::TemplateSpecialization: case Type::Elaborated: case Type::QualifiedName: @@ -1318,6 +1270,21 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, return llvm::DIType(); } +/// CreateMemberType - Create new member and increase Offset by FType's size. +llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, + llvm::StringRef Name, + uint64_t *Offset) { + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + uint64_t FieldSize = CGM.getContext().getTypeSize(FType); + unsigned FieldAlign = CGM.getContext().getTypeAlign(FType); + llvm::DIType Ty = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, + Unit, Name, Unit, 0, + FieldSize, FieldAlign, + *Offset, 0, FieldTy); + *Offset += FieldSize; + return Ty; +} + /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, @@ -1341,17 +1308,15 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, } } Name = getFunctionName(FD); - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); // Use mangled name as linkage name for c/c++ functions. CGM.getMangledName(LinkageName, GD); } else { // Use llvm function name as linkage name. Name = Fn->getName(); LinkageName.setString(Name); - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); } + if (!Name.empty() && Name[0] == '\01') + Name = Name.substr(1); // It is expected that CurLoc is set before using EmitFunctionStart. // Usually, CurLoc points to the left bracket location of compound @@ -1437,72 +1402,19 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__forwarding", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset)); FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__size", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__copy_helper", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__destroy_helper", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper", + &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper", + &FieldOffset)); } CharUnits Align = CGM.getContext().getDeclAlign(VD); @@ -1517,20 +1429,12 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, llvm::APInt pad(32, NumPaddingBytes); FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, - Unit, "", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); } } FType = Type; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align.getQuantity()*8; @@ -1558,13 +1462,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::Value *Storage, CGBuilderTy &Builder) { assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel) - return; - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); llvm::DIType Ty; uint64_t XOffset = 0; @@ -1608,11 +1505,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, const ValueDecl *VD = BDRE->getDecl(); assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) + if (Builder.GetInsertBlock() == 0) return; uint64_t XOffset = 0; @@ -1708,7 +1601,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = Var->getName(); + llvm::StringRef DeclName = D->getName(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast(D->getDeclContext()), Unit); DebugFactory.CreateGlobalVariable(DContext, DeclName, diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 8397245..c16379a 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -112,7 +112,7 @@ class CGDebugInfo { void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl &E); - void CollectVtableInfo(const CXXRecordDecl *Decl, + void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl &EltTys); @@ -196,13 +196,17 @@ private: /// CreateTypeNode - Create type metadata for a source language type. llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F); + /// CreateMemberType - Create new member and increase Offset by FType's size. + llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, + llvm::StringRef Name, uint64_t *Offset); + /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. llvm::StringRef getFunctionName(const FunctionDecl *FD); - /// getVtableName - Get vtable name for the given Class. - llvm::StringRef getVtableName(const CXXRecordDecl *Decl); + /// getVTableName - Get vtable name for the given Class. + llvm::StringRef getVTableName(const CXXRecordDecl *Decl); }; } // namespace CodeGen diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 07d219f..ba3a2b4 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -31,11 +31,44 @@ using namespace CodeGen; void CodeGenFunction::EmitDecl(const Decl &D) { switch (D.getKind()) { - default: - CGM.ErrorUnsupported(&D, "decl"); - return; + case Decl::TranslationUnit: + case Decl::Namespace: + case Decl::UnresolvedUsingTypename: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + case Decl::TemplateTypeParm: + case Decl::UnresolvedUsingValue: + case Decl::NonTypeTemplateParm: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::Field: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: case Decl::ParmVar: - assert(0 && "Parmdecls should not be in declstmts!"); + case Decl::ImplicitParam: + case Decl::ClassTemplate: + case Decl::FunctionTemplate: + case Decl::TemplateTemplateParm: + case Decl::ObjCMethod: + case Decl::ObjCCategory: + case Decl::ObjCProtocol: + case Decl::ObjCInterface: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCProperty: + case Decl::ObjCCompatibleAlias: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::ObjCClass: + case Decl::ObjCForwardProtocol: + case Decl::FileScopeAsm: + case Decl::Friend: + case Decl::FriendTemplate: + case Decl::Block: + + assert(0 && "Declaration not should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; case Decl::Enum: // enum X; @@ -44,6 +77,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Using: // using X; [C++] case Decl::UsingShadow: case Decl::UsingDirective: // using namespace X; [C++] + case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] // None of these decls require codegen support. return; @@ -197,6 +231,9 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) { + // Bail out early if the block is unreachable. + if (!Builder.GetInsertBlock()) return; + llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); @@ -205,6 +242,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, // Store into LocalDeclMap before generating initializer to handle // circular references. DMEntry = GV; + if (getContext().getLangOptions().CPlusPlus) + CGM.setStaticLocalDeclAddress(&D, GV); // Make sure to evaluate VLA bounds now so that we have them for later. // @@ -610,6 +649,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs()) if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { + llvm::Value *Loc = DeclPtr; + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + if (!ClassDecl->hasTrivialDestructor()) { const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); @@ -622,7 +666,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); + Builder.CreateBitCast(Loc, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); // Make sure to jump to the exit block. @@ -634,20 +678,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); + Builder.CreateBitCast(Loc, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); } } else { { DelayedCleanupBlock Scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, + Loc); // Make sure to jump to the exit block. EmitBranch(Scope.getCleanupExitBlock()); } if (Exceptions) { EHCleanupBlock Cleanup(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, + Loc); } } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 40c18ca..f6c805f 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -219,9 +219,14 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn, SourceLocation()); // Emit the dtors, in reverse order from construction. - for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) - Builder.CreateCall(DtorsAndObjects[e - i - 1].first, - DtorsAndObjects[e - i - 1].second); + for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) { + llvm::Constant *Callee = DtorsAndObjects[e - i - 1].first; + llvm::CallInst *CI = Builder.CreateCall(Callee, + DtorsAndObjects[e - i - 1].second); + // Make sure the call and the callee agree on calling convention. + if (llvm::Function *F = dyn_cast(Callee)) + CI->setCallingConv(F->getCallingConv()); + } FinishFunction(); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 1e15066..c1d05bf 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -122,82 +122,71 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); } -// CopyObject - Utility to copy an object. Calls copy constructor as necessary. -// DestPtr is casted to the right type. -static void CopyObject(CodeGenFunction &CGF, const Expr *E, - llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { - 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(); - - CGF.Builder.CreateStore(Value, - CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); - } else { - const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); - const CXXRecordDecl *RD = - cast(ObjectType->getAs()->getDecl()); - - llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); - if (RD->hasTrivialCopyConstructor()) { - CGF.EmitAggExpr(E, This, false); - } else if (CXXConstructorDecl *CopyCtor - = RD->getCopyConstructor(CGF.getContext(), 0)) { - llvm::Value *CondPtr = 0; - if (CGF.Exceptions) { - CodeGenFunction::EHCleanupBlock Cleanup(CGF); - llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); - - llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free"); - llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); - CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), - "doEHfree"); - - CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr), - CondBlock, Cont); - CGF.EmitBlock(CondBlock); - - // Load the exception pointer. - llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); - CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); - - CGF.EmitBlock(Cont); - } - - if (CondPtr) - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), - CondPtr); - - llvm::Value *Src = CGF.EmitLValue(E).getAddress(); - - if (CondPtr) - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), - CondPtr); - - llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); - CGF.setInvokeDest(TerminateHandler); - - // 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())); - const FunctionProtoType *FPT - = CopyCtor->getType()->getAs(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, CopyCtor); - CGF.setInvokeDest(PrevLandingPad); - } else - llvm_unreachable("uncopyable object"); +// Emits an exception expression into the given location. This +// differs from EmitAnyExprToMem only in that, if a final copy-ctor +// call is required, an exception within that copy ctor causes +// std::terminate to be invoked. +static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, + llvm::Value *ExnLoc) { + // We want to release the allocated exception object if this + // expression throws. We do this by pushing an EH-only cleanup + // block which, furthermore, deactivates itself after the expression + // is complete. + llvm::AllocaInst *ShouldFreeVar = + CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), + "should-free-exnobj.var"); + CGF.InitTempAlloca(ShouldFreeVar, + llvm::ConstantInt::getFalse(CGF.getLLVMContext())); + + // A variable holding the exception pointer. This is necessary + // because the throw expression does not necessarily dominate the + // cleanup, for example if it appears in a conditional expression. + llvm::AllocaInst *ExnLocVar = + CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var"); + + llvm::BasicBlock *SavedInvokeDest = CGF.getInvokeDest(); + { + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj"); + llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done"); + + llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar, + "should-free-exnobj"); + CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB); + CGF.EmitBlock(FreeBB); + llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj"); + CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal); + CGF.EmitBlock(DoneBB); } + llvm::BasicBlock *Cleanup = CGF.getInvokeDest(); + + CGF.Builder.CreateStore(ExnLoc, ExnLocVar); + CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), + ShouldFreeVar); + + // __cxa_allocate_exception returns a void*; we need to cast this + // to the appropriate type for the object. + const llvm::Type *Ty = CGF.ConvertType(E->getType())->getPointerTo(); + llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty); + + // FIXME: this isn't quite right! If there's a final unelided call + // to a copy constructor, then according to [except.terminate]p1 we + // must call std::terminate() if that constructor throws, because + // technically that copy occurs after the exception expression is + // evaluated but before the exception is caught. But the best way + // to handle that is to teach EmitAggExpr to do the final copy + // differently if it can't be elided. + CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false); + + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), + ShouldFreeVar); + + // Pop the cleanup block if it's still the top of the cleanup stack. + // Otherwise, temporaries have been created and our cleanup will get + // properly removed in time. + // TODO: this is not very resilient. + if (CGF.getInvokeDest() == Cleanup) + CGF.setInvokeDest(SavedInvokeDest); } // CopyObject - Utility to copy an object. Calls copy constructor as necessary. @@ -270,7 +259,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Now allocate the exception object. const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; + uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity(); llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); llvm::Value *ExceptionPtr = @@ -278,17 +267,24 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - llvm::Value *ExceptionPtrPtr = - CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); - Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); - - - CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); + EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr); // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType); - llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); + llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true); + + // The address of the destructor. If the exception type has a + // trivial destructor (or isn't a record), we just pass null. + llvm::Constant *Dtor = 0; + if (const RecordType *RecordTy = ThrowType->getAs()) { + CXXRecordDecl *Record = cast(RecordTy->getDecl()); + if (!Record->hasTrivialDestructor()) { + CXXDestructorDecl *DtorD = Record->getDestructor(getContext()); + Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete); + Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy); + } + } + if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy); if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); @@ -375,7 +371,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { QualType Ty = Proto->getExceptionType(i); QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); - llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true); SelectorArgs.push_back(EHType); } if (Proto->getNumExceptions()) @@ -498,7 +494,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, // are ignored. QualType CaughtType = C->getCaughtType().getNonReferenceType(); llvm::Value *EHTypeInfo - = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType()); + = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType(), true); SelectorArgs.push_back(EHTypeInfo); } else { // null indicates catch all @@ -649,38 +645,46 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, } CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { - llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); - CGF.EmitBranch(Cont1); CGF.setInvokeDest(PreviousInvokeDest); + llvm::BasicBlock *EndOfCleanup = CGF.Builder.GetInsertBlock(); - CGF.EmitBlock(CleanupHandler); - + // Jump to the beginning of the cleanup. + CGF.Builder.SetInsertPoint(CleanupHandler, CleanupHandler->begin()); + + // The libstdc++ personality function. + // TODO: generalize to work with other libraries. llvm::Constant *Personality = CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty (CGF.VMContext), true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + + // %exception = call i8* @llvm.eh.exception() + // Magic intrinsic which tells gives us a handle to the caught + // exception. llvm::Value *llvm_eh_exception = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); - llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); - const llvm::IntegerType *Int8Ty; - const llvm::PointerType *PtrToInt8Ty; - Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); - // C string type. Used in lots of places. - PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); - llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + + llvm::Constant *Null = llvm::ConstantPointerNull::get(CGF.PtrToInt8Ty); + + // %ignored = call i32 @llvm.eh.selector(i8* %exception, + // i8* @__gxx_personality_v0, + // i8* null) + // Magic intrinsic which tells LLVM that this invoke landing pad is + // just a cleanup block. llvm::Value *Args[] = { Exc, Personality, Null }; + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); - CGF.EmitBlock(CleanupEntryBB); - - CGF.EmitBlock(Cont1); + // And then we fall through into the code that the user put there. + // Jump back to the end of the cleanup. + CGF.Builder.SetInsertPoint(EndOfCleanup); + // Rethrow the exception. if (CGF.getInvokeDest()) { llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, @@ -688,10 +692,15 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { CGF.EmitBlock(Cont); } else CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); - CGF.Builder.CreateUnreachable(); - CGF.EmitBlock(Cont); + // Resume inserting where we started, but put the new cleanup + // handler in place. + if (PreviousInsertionBlock) + CGF.Builder.SetInsertPoint(PreviousInsertionBlock); + else + CGF.Builder.ClearInsertionPoint(); + if (CGF.Exceptions) CGF.setInvokeDest(CleanupHandler); } @@ -700,12 +709,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { if (TerminateHandler) return TerminateHandler; - llvm::BasicBlock *Cont = 0; - - if (HaveInsertPoint()) { - Cont = createBasicBlock("cont"); - EmitBranch(Cont); - } + // We don't want to change anything at the current location, so + // save it aside and clear the insert point. + llvm::BasicBlock *SavedInsertBlock = Builder.GetInsertBlock(); + llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint(); + Builder.ClearInsertionPoint(); llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -735,11 +743,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { TerminateCall->setDoesNotThrow(); Builder.CreateUnreachable(); - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); - - if (Cont) - EmitBlock(Cont); + // Restore the saved insertion state. + Builder.SetInsertPoint(SavedInsertBlock, SavedInsertPoint); return TerminateHandler; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 0aa4438..9ade916 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -37,6 +37,13 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } +void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var, + llvm::Value *Init) { + llvm::StoreInst *Store = new llvm::StoreInst(Init, Var); + llvm::BasicBlock *Block = AllocaInsertPt->getParent(); + Block->getInstList().insertAfter(&*AllocaInsertPt, Store); +} + llvm::Value *CodeGenFunction::CreateIRTemp(QualType Ty, const llvm::Twine &Name) { llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name); @@ -111,6 +118,23 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, IsInitializer); } +/// EmitAnyExprToMem - Evaluate an expression into a given memory +/// location. +void CodeGenFunction::EmitAnyExprToMem(const Expr *E, + llvm::Value *Location, + bool IsLocationVolatile, + bool IsInit) { + if (E->getType()->isComplexType()) + EmitComplexExprIntoAddr(E, Location, IsLocationVolatile); + else if (hasAggregateLLVMType(E->getType())) + EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit); + else { + RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false)); + LValue LV = LValue::MakeAddr(Location, MakeQualifiers(E->getType())); + EmitStoreThroughLValue(RV, LV, E->getType()); + } +} + RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer) { bool ShouldDestroyTemporaries = false; @@ -150,16 +174,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, PopCXXTemporary(); } } else { - const CXXRecordDecl *BaseClassDecl = 0; + const CXXBaseSpecifierArray *BasePath = 0; const CXXRecordDecl *DerivedClassDecl = 0; if (const CastExpr *CE = dyn_cast(E->IgnoreParenNoopCasts(getContext()))) { if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { E = CE->getSubExpr(); - - BaseClassDecl = - cast(CE->getType()->getAs()->getDecl()); + + BasePath = &CE->getBasePath(); DerivedClassDecl = cast(E->getType()->getAs()->getDecl()); } @@ -185,6 +208,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, { DelayedCleanupBlock Scope(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Val.getAggregateAddr()); // Make sure to jump to the exit block. @@ -193,6 +217,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (Exceptions) { EHCleanupBlock Cleanup(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Val.getAggregateAddr()); } } @@ -201,10 +226,10 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } // Check if need to perform the derived-to-base cast. - if (BaseClassDecl) { + if (BasePath) { llvm::Value *Derived = Val.getAggregateAddr(); llvm::Value *Base = - GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, + GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath, /*NullCheckValue=*/false); return RValue::get(Base); } @@ -240,18 +265,15 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { if (!CatchUndefined) return; - const llvm::IntegerType *Size_tTy + const llvm::Type *Size_tTy = llvm::IntegerType::get(VMContext, LLVMPointerWidth); Address = Builder.CreateBitCast(Address, PtrToInt8Ty); - const llvm::Type *ResType[] = { - Size_tTy - }; - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1); - const llvm::IntegerType *IntTy = cast( - CGM.getTypes().ConvertType(CGM.getContext().IntTy)); + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, &Size_tTy, 1); + const llvm::IntegerType *Int1Ty = llvm::IntegerType::get(VMContext, 1); + // In time, people may want to control this and use a 1 here. - llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0); + llvm::Value *Arg = llvm::ConstantInt::get(Int1Ty, 0); llvm::Value *C = Builder.CreateCall2(F, Address, Arg); llvm::BasicBlock *Cont = createBasicBlock(); llvm::BasicBlock *Check = createBasicBlock(); @@ -457,6 +479,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitObjCIsaExpr(cast(E)); case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast(E)); + case Expr::CompoundAssignOperatorClass: + return EmitCompoundAssignOperatorLValue(cast(E)); case Expr::CallExprClass: case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: @@ -606,63 +630,73 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType) { const CGBitFieldInfo &Info = LV.getBitFieldInfo(); - unsigned StartBit = Info.Start; - unsigned BitfieldSize = Info.Size; - llvm::Value *Ptr = LV.getBitFieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); + // Get the output type. + const llvm::Type *ResLTy = ConvertType(ExprType); + unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); - // In some cases the bitfield may straddle two memory locations. Currently we - // load the entire bitfield, then do the magic to sign-extend it if - // necessary. This results in somewhat more code than necessary for the common - // case (one load), since two shifts accomplish both the masking and sign - // extension. - unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); - llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp"); + // Compute the result as an OR of all of the individual component accesses. + llvm::Value *Res = 0; + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); - // Shift to proper location. - if (StartBit) - Val = Builder.CreateLShr(Val, StartBit, "bf.lo"); + // Get the field pointer. + llvm::Value *Ptr = LV.getBitFieldBaseAddr(); - // Mask off unused bits. - llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, LowBits)); - Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared"); + // Only offset by the field index if used, so that incoming values are not + // required to be structures. + if (AI.FieldIndex) + Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); - // Fetch the high bits if necessary. - if (LowBits < BitfieldSize) { - unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, - LV.isVolatileQualified(), - "tmp"); + // Offset by the byte offset, if used. + if (AI.FieldByteOffset) { + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Ptr = Builder.CreateBitCast(Ptr, i8PTy); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + } - // Mask off unused bits. - llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, HighBits)); - HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); + // Cast to the access type. + const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth, + ExprType.getAddressSpace()); + Ptr = Builder.CreateBitCast(Ptr, PTy); - // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, LowBits); - Val = Builder.CreateOr(Val, HighVal, "bf.val"); - } + // Perform the load. + llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified()); + if (AI.AccessAlignment) + Load->setAlignment(AI.AccessAlignment); - // Sign extend if necessary. - if (Info.IsSigned) { - llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy, - EltTySize - BitfieldSize); - Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits), - ExtraBits, "bf.val.sext"); + // Shift out unused low bits and mask out unused high bits. + llvm::Value *Val = Load; + if (AI.FieldBitStart) + Val = Builder.CreateLShr(Load, AI.FieldBitStart); + Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth, + AI.TargetBitWidth), + "bf.clear"); + + // Extend or truncate to the target size. + if (AI.AccessWidth < ResSizeInBits) + Val = Builder.CreateZExt(Val, ResLTy); + else if (AI.AccessWidth > ResSizeInBits) + Val = Builder.CreateTrunc(Val, ResLTy); + + // Shift into place, and OR into the result. + if (AI.TargetBitOffset) + Val = Builder.CreateShl(Val, AI.TargetBitOffset); + Res = Res ? Builder.CreateOr(Res, Val) : Val; } - // The bitfield type and the normal type differ when the storage sizes differ - // (currently just _Bool). - Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp"); + // If the bit-field is signed, perform the sign-extension. + // + // FIXME: This can easily be folded into the load of the high bits, which + // could also eliminate the mask of high bits in some situations. + if (Info.isSigned()) { + unsigned ExtraBits = ResSizeInBits - Info.getSize(); + if (ExtraBits) + Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits), + ExtraBits, "bf.val.sext"); + } - return RValue::get(Val); + return RValue::get(Res); } RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, @@ -783,88 +817,103 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty, llvm::Value **Result) { const CGBitFieldInfo &Info = Dst.getBitFieldInfo(); - unsigned StartBit = Info.Start; - unsigned BitfieldSize = Info.Size; - llvm::Value *Ptr = Dst.getBitFieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); + // Get the output type. + const llvm::Type *ResLTy = ConvertTypeForMem(Ty); + unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); - // Get the new value, cast to the appropriate type and masked to exactly the - // size of the bit-field. + // Get the source value, truncated to the width of the bit-field. llvm::Value *SrcVal = Src.getScalarVal(); - llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp"); - llvm::Constant *Mask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize)); - NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value"); + + if (Ty->isBooleanType()) + SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false); + + SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits, + Info.getSize()), + "bf.value"); // Return the new value of the bit-field, if requested. if (Result) { // Cast back to the proper type for result. - const llvm::Type *SrcTy = SrcVal->getType(); - llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false, - "bf.reload.val"); + const llvm::Type *SrcTy = Src.getScalarVal()->getType(); + llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false, + "bf.reload.val"); // Sign extend if necessary. - if (Info.IsSigned) { - unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy); - llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy, - SrcTySize - BitfieldSize); - SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits), - ExtraBits, "bf.reload.sext"); + if (Info.isSigned()) { + unsigned ExtraBits = ResSizeInBits - Info.getSize(); + if (ExtraBits) + ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits), + ExtraBits, "bf.reload.sext"); } - *Result = SrcTrunc; + *Result = ReloadVal; } - // In some cases the bitfield may straddle two memory locations. Emit the low - // part first and check to see if the high needs to be done. - unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); - llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), - "bf.prev.low"); - - // Compute the mask for zero-ing the low part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(VMContext, - ~llvm::APInt::getBitsSet(EltTySize, StartBit, StartBit + LowBits)); + // Iterate over the components, writing each piece to memory. + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); - // Compute the new low part as - // LowVal = (LowVal & InvMask) | (NewVal << StartBit), - // with the shift of NewVal implicitly stripping the high bits. - llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, StartBit, "bf.value.lo"); - LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); - LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); + // Get the field pointer. + llvm::Value *Ptr = Dst.getBitFieldBaseAddr(); - // Write back. - Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified()); + // Only offset by the field index if used, so that incoming values are not + // required to be structures. + if (AI.FieldIndex) + Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); - // If the low part doesn't cover the bitfield emit a high part. - if (LowBits < BitfieldSize) { - unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, - Dst.isVolatileQualified(), - "bf.prev.hi"); - - // Compute the mask for zero-ing the high part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(VMContext, ~llvm::APInt::getLowBitsSet(EltTySize, - HighBits)); + // Offset by the byte offset, if used. + if (AI.FieldByteOffset) { + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Ptr = Builder.CreateBitCast(Ptr, i8PTy); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + } - // Compute the new high part as - // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits), - // where the high bits of NewVal have already been cleared and the - // shift stripping the low bits. - llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, LowBits, "bf.value.high"); - HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); - HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); + // Cast to the access type. + const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth, + Ty.getAddressSpace()); + Ptr = Builder.CreateBitCast(Ptr, PTy); + + // Extract the piece of the bit-field value to write in this access, limited + // to the values that are part of this access. + llvm::Value *Val = SrcVal; + if (AI.TargetBitOffset) + Val = Builder.CreateLShr(Val, AI.TargetBitOffset); + Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits, + AI.TargetBitWidth)); + + // Extend or truncate to the access size. + const llvm::Type *AccessLTy = + llvm::Type::getIntNTy(VMContext, AI.AccessWidth); + if (ResSizeInBits < AI.AccessWidth) + Val = Builder.CreateZExt(Val, AccessLTy); + else if (ResSizeInBits > AI.AccessWidth) + Val = Builder.CreateTrunc(Val, AccessLTy); + + // Shift into the position in memory. + if (AI.FieldBitStart) + Val = Builder.CreateShl(Val, AI.FieldBitStart); + + // If necessary, load and OR in bits that are outside of the bit-field. + if (AI.TargetBitWidth != AI.AccessWidth) { + llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified()); + if (AI.AccessAlignment) + Load->setAlignment(AI.AccessAlignment); + + // Compute the mask for zeroing the bits that are part of the bit-field. + llvm::APInt InvMask = + ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart, + AI.FieldBitStart + AI.TargetBitWidth); + + // Apply the mask and OR in to the value to write. + Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val); + } - // Write back. - Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified()); + // Write the value. + llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr, + Dst.isVolatileQualified()); + if (AI.AccessAlignment) + Store->setAlignment(AI.AccessAlignment); } } @@ -1084,6 +1133,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr(); llvm::Value *V = LocalDeclMap[VD]; + if (!V && getContext().getLangOptions().CPlusPlus && + VD->isStaticLocal()) + V = CGM.getStaticLocalDeclAddress(VD); assert(V && "DeclRefExpr not entered in LocalDeclMap?"); Qualifiers Quals = MakeQualifiers(E->getType()); @@ -1474,19 +1526,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(Field->getParent()); const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - - // FIXME: CodeGenTypes should expose a method to get the appropriate type for - // FieldTy (the appropriate type is ABI-dependent). - const llvm::Type *FieldTy = - CGM.getTypes().ConvertTypeForMem(Field->getType()); - const llvm::PointerType *BaseTy = - cast(BaseValue->getType()); - unsigned AS = BaseTy->getAddressSpace(); - BaseValue = Builder.CreateBitCast(BaseValue, - llvm::PointerType::get(FieldTy, AS)); - llvm::Value *V = Builder.CreateConstGEP1_32(BaseValue, Info.FieldNo); - - return LValue::MakeBitfield(V, Info, + return LValue::MakeBitfield(BaseValue, Info, Field->getType().getCVRQualifiers()|CVRQualifiers); } @@ -1548,12 +1588,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); - if (E->getType()->isComplexType()) - EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); - else if (hasAggregateLLVMType(E->getType())) - EmitAnyExpr(InitExpr, DeclPtr, false); - else - EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType()); + EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false); return Result; } @@ -1647,27 +1682,19 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { E->getSubExpr()->getType()->getAs(); CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); - - const RecordType *BaseClassTy = E->getType()->getAs(); - CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); LValue LV = EmitLValue(E->getSubExpr()); // Perform the derived-to-base conversion llvm::Value *Base = GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl, - BaseClassDecl, /*NullCheckValue=*/false); + E->getBasePath(), /*NullCheckValue=*/false); return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } case CastExpr::CK_ToUnion: return EmitAggExprToLValue(E); case CastExpr::CK_BaseToDerived: { - const RecordType *BaseClassTy = - E->getSubExpr()->getType()->getAs(); - CXXRecordDecl *BaseClassDecl = - cast(BaseClassTy->getDecl()); - const RecordType *DerivedClassTy = E->getType()->getAs(); CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); @@ -1676,8 +1703,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // Perform the base-to-derived conversion llvm::Value *Derived = - GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl, - DerivedClassDecl, /*NullCheckValue=*/false); + GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, + E->getBasePath(),/*NullCheckValue=*/false); return LValue::MakeAddr(Derived, MakeQualifiers(E->getType())); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 4d5160f..d1b0dff 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -263,7 +263,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { std::swap(DerivedDecl, BaseDecl); if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->getBasePath())) { if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); else @@ -321,6 +321,11 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { (void) MPT; assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); + + // The creation of member function pointers has no side effects; if + // there is no destination pointer, we have nothing to do. + if (!DestPtr) + return; const DeclRefExpr *DRE = cast(E->getSubExpr()); const CXXMethodDecl *MD = @@ -329,17 +334,23 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { const llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); + llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); llvm::Value *FuncPtr; if (MD->isVirtual()) { - int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD); + int64_t Index = CGF.CGM.getVTables().getMethodVTableIndex(MD); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGF.CGM.getContext().Target.getPointerWidth(0) / 8; + // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. // For a virtual function, it is 1 plus the virtual table offset // (in bytes) of the function, represented as a ptrdiff_t. - FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); + FuncPtr = llvm::ConstantInt::get(PtrDiffTy, + (Index * PointerWidthInBytes) + 1); } else { const FunctionProtoType *FPT = MD->getType()->getAs(); const llvm::Type *Ty = @@ -738,6 +749,14 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, bool isVolatile) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); + // Ignore empty classes in C++. + if (getContext().getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs()) { + if (cast(RT->getDecl())->isEmpty()) + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 1fd1da8..b57cdc9 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -205,20 +205,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); EmitBlock(FnVirtual); - const llvm::Type *VtableTy = + const llvm::Type *VTableTy = FTy->getPointerTo()->getPointerTo(); - llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo()); - Vtable = Builder.CreateLoad(Vtable); + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); + VTable = Builder.CreateLoad(VTable); - Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy); - llvm::Value *VtableOffset = + VTable = Builder.CreateBitCast(VTable, Int8PtrTy); + llvm::Value *VTableOffset = Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1)); - Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn"); - Vtable = Builder.CreateBitCast(Vtable, VtableTy); + VTable = Builder.CreateGEP(VTable, VTableOffset, "fn"); + VTable = Builder.CreateBitCast(VTable, VTableTy); - llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn"); + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); EmitBranch(FnEnd); EmitBlock(FnNonVirtual); @@ -316,17 +316,22 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(Dest, BasePtr); + Builder.CreateBitCast(Dest, BasePtr); EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, E->arg_begin(), E->arg_end()); } - else + else { + CXXCtorType Type = + (E->getConstructionKind() == CXXConstructExpr::CK_Complete) + ? Ctor_Complete : Ctor_Base; + bool ForVirtualBase = + E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; + // Call the constructor. - EmitCXXConstructorCall(CD, - E->isBaseInitialization()? Ctor_Base : Ctor_Complete, - Dest, + EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest, E->arg_begin(), E->arg_end()); + } } static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { @@ -460,18 +465,20 @@ 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; + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + if (!Ctor->getParent()->hasTrivialConstructor()) + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + return; + } } QualType AllocType = E->getAllocatedType(); if (CXXConstructorDecl *Ctor = E->getConstructor()) { - CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, + NewPtr, E->constructor_arg_begin(), E->constructor_arg_end()); return; @@ -760,7 +767,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { // The dtor took care of deleting the object. ShouldCallDelete = false; } else - EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + Ptr); } } } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 172a77d..2595ff0 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -27,359 +27,387 @@ using namespace clang; using namespace CodeGen; -namespace { +//===----------------------------------------------------------------------===// +// ConstStructBuilder +//===----------------------------------------------------------------------===// + +namespace { class ConstStructBuilder { CodeGenModule &CGM; CodeGenFunction *CGF; bool Packed; - unsigned NextFieldOffsetInBytes; - unsigned LLVMStructAlignment; - std::vector Elements; - +public: + static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + InitListExpr *ILE); + +private: ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0), LLVMStructAlignment(1) { } bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - uint64_t FieldOffsetInBytes = FieldOffset / 8; + llvm::Constant *InitExpr); - assert(NextFieldOffsetInBytes <= FieldOffsetInBytes - && "Field offset mismatch!"); + bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitExpr); - // Emit the field. - llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); - if (!C) - return false; + void AppendPadding(uint64_t NumBytes); - unsigned FieldAlignment = getAlignment(C); + void AppendTailPadding(uint64_t RecordSize); - // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + void ConvertStructToPacked(); + + bool Build(InitListExpr *ILE); - if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { - assert(!Packed && "Alignment is wrong even with a packed struct!"); + unsigned getAlignment(const llvm::Constant *C) const { + if (Packed) return 1; + return CGM.getTargetData().getABITypeAlignment(C->getType()); + } - // Convert the struct to a packed struct. - ConvertStructToPacked(); - - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + uint64_t getSizeInBytes(const llvm::Constant *C) const { + return CGM.getTargetData().getTypeAllocSize(C->getType()); + } +}; - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { - // We need to append padding. - AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); +bool ConstStructBuilder:: +AppendField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { + uint64_t FieldOffsetInBytes = FieldOffset / 8; - assert(NextFieldOffsetInBytes == FieldOffsetInBytes && - "Did not add enough padding!"); + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes + && "Field offset mismatch!"); - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + // Emit the field. + if (!InitCst) + return false; - // Add the field. - Elements.push_back(C); - NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); - - if (Packed) - assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); - else - LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); + unsigned FieldAlignment = getAlignment(InitCst); - return true; - } + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); - bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - llvm::ConstantInt *CI = - cast_or_null(CGM.EmitConstantExpr(InitExpr, - Field->getType(), - CGF)); - // FIXME: Can this ever happen? - if (!CI) - return false; - - if (FieldOffset > NextFieldOffsetInBytes * 8) { - // We need to add padding. - uint64_t NumBytes = - llvm::RoundUpToAlignment(FieldOffset - - NextFieldOffsetInBytes * 8, 8) / 8; + if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { + assert(!Packed && "Alignment is wrong even with a packed struct!"); - AppendPadding(NumBytes); - } + // Convert the struct to a packed struct. + ConvertStructToPacked(); + + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // We need to append padding. + AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); - llvm::APInt FieldValue = CI->getValue(); + assert(NextFieldOffsetInBytes == FieldOffsetInBytes && + "Did not add enough padding!"); - // Promote the size of FieldValue if necessary - // FIXME: This should never occur, but currently it can because initializer - // constants are cast to bool, and because clang is not enforcing bitfield - // width limits. - if (FieldSize > FieldValue.getBitWidth()) - FieldValue.zext(FieldSize); + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - // Truncate the size of FieldValue to the bit field size. - if (FieldSize < FieldValue.getBitWidth()) - FieldValue.trunc(FieldSize); + // Add the field. + Elements.push_back(InitCst); + NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + + getSizeInBytes(InitCst); + + if (Packed) + assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); + else + LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); - if (FieldOffset < NextFieldOffsetInBytes * 8) { - // Either part of the field or the entire field can go into the previous - // byte. - assert(!Elements.empty() && "Elements can't be empty!"); + return true; +} - unsigned BitsInPreviousByte = - NextFieldOffsetInBytes * 8 - FieldOffset; +bool ConstStructBuilder:: + AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { + llvm::ConstantInt *CI = cast_or_null(InitCst); + // FIXME: Can this ever happen? + if (!CI) + return false; - bool FitsCompletelyInPreviousByte = - BitsInPreviousByte >= FieldValue.getBitWidth(); + if (FieldOffset > NextFieldOffsetInBytes * 8) { + // We need to add padding. + uint64_t NumBytes = + llvm::RoundUpToAlignment(FieldOffset - + NextFieldOffsetInBytes * 8, 8) / 8; - llvm::APInt Tmp = FieldValue; + AppendPadding(NumBytes); + } - if (!FitsCompletelyInPreviousByte) { - unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); - if (CGM.getTargetData().isBigEndian()) { - Tmp = Tmp.lshr(NewFieldWidth); - Tmp.trunc(BitsInPreviousByte); + llvm::APInt FieldValue = CI->getValue(); - // We want the remaining high bits. - FieldValue.trunc(NewFieldWidth); - } else { - Tmp.trunc(BitsInPreviousByte); + // Promote the size of FieldValue if necessary + // FIXME: This should never occur, but currently it can because initializer + // constants are cast to bool, and because clang is not enforcing bitfield + // width limits. + if (FieldSize > FieldValue.getBitWidth()) + FieldValue.zext(FieldSize); - // We want the remaining low bits. - FieldValue = FieldValue.lshr(BitsInPreviousByte); - FieldValue.trunc(NewFieldWidth); - } - } + // Truncate the size of FieldValue to the bit field size. + if (FieldSize < FieldValue.getBitWidth()) + FieldValue.trunc(FieldSize); - Tmp.zext(8); - if (CGM.getTargetData().isBigEndian()) { - if (FitsCompletelyInPreviousByte) - Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); - } else { - Tmp = Tmp.shl(8 - BitsInPreviousByte); - } + if (FieldOffset < NextFieldOffsetInBytes * 8) { + // Either part of the field or the entire field can go into the previous + // byte. + assert(!Elements.empty() && "Elements can't be empty!"); - // Or in the bits that go into the previous byte. - if (llvm::ConstantInt *Val = dyn_cast(Elements.back())) - Tmp |= Val->getValue(); - else - assert(isa(Elements.back())); + unsigned BitsInPreviousByte = + NextFieldOffsetInBytes * 8 - FieldOffset; - Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); + bool FitsCompletelyInPreviousByte = + BitsInPreviousByte >= FieldValue.getBitWidth(); - if (FitsCompletelyInPreviousByte) - return true; - } + llvm::APInt Tmp = FieldValue; - while (FieldValue.getBitWidth() > 8) { - llvm::APInt Tmp; + if (!FitsCompletelyInPreviousByte) { + unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; if (CGM.getTargetData().isBigEndian()) { - // We want the high bits. - Tmp = FieldValue; - Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); - Tmp.trunc(8); + Tmp = Tmp.lshr(NewFieldWidth); + Tmp.trunc(BitsInPreviousByte); + + // We want the remaining high bits. + FieldValue.trunc(NewFieldWidth); } else { - // We want the low bits. - Tmp = FieldValue; - Tmp.trunc(8); + Tmp.trunc(BitsInPreviousByte); - FieldValue = FieldValue.lshr(8); + // We want the remaining low bits. + FieldValue = FieldValue.lshr(BitsInPreviousByte); + FieldValue.trunc(NewFieldWidth); } - - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); - NextFieldOffsetInBytes++; - - FieldValue.trunc(FieldValue.getBitWidth() - 8); } - assert(FieldValue.getBitWidth() > 0 && - "Should have at least one bit left!"); - assert(FieldValue.getBitWidth() <= 8 && - "Should not have more than a byte left!"); + Tmp.zext(8); + if (CGM.getTargetData().isBigEndian()) { + if (FitsCompletelyInPreviousByte) + Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); + } else { + Tmp = Tmp.shl(8 - BitsInPreviousByte); + } - if (FieldValue.getBitWidth() < 8) { - if (CGM.getTargetData().isBigEndian()) { - unsigned BitWidth = FieldValue.getBitWidth(); + // Or in the bits that go into the previous byte. + if (llvm::ConstantInt *Val = dyn_cast(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa(Elements.back())); - FieldValue.zext(8); - FieldValue = FieldValue << (8 - BitWidth); - } else - FieldValue.zext(8); - } + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); - // Append the last element. - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), - FieldValue)); - NextFieldOffsetInBytes++; - return true; + if (FitsCompletelyInPreviousByte) + return true; } - void AppendPadding(uint64_t NumBytes) { - if (!NumBytes) - return; + while (FieldValue.getBitWidth() > 8) { + llvm::APInt Tmp; + + if (CGM.getTargetData().isBigEndian()) { + // We want the high bits. + Tmp = FieldValue; + Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); + Tmp.trunc(8); + } else { + // We want the low bits. + Tmp = FieldValue; + Tmp.trunc(8); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + FieldValue = FieldValue.lshr(8); + } - llvm::Constant *C = llvm::UndefValue::get(Ty); - Elements.push_back(C); - assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); + NextFieldOffsetInBytes++; - NextFieldOffsetInBytes += getSizeInBytes(C); + FieldValue.trunc(FieldValue.getBitWidth() - 8); } - void AppendTailPadding(uint64_t RecordSize) { - assert(RecordSize % 8 == 0 && "Invalid record size!"); + assert(FieldValue.getBitWidth() > 0 && + "Should have at least one bit left!"); + assert(FieldValue.getBitWidth() <= 8 && + "Should not have more than a byte left!"); - uint64_t RecordSizeInBytes = RecordSize / 8; - assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + if (FieldValue.getBitWidth() < 8) { + if (CGM.getTargetData().isBigEndian()) { + unsigned BitWidth = FieldValue.getBitWidth(); - unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; - AppendPadding(NumPadBytes); + FieldValue.zext(8); + FieldValue = FieldValue << (8 - BitWidth); + } else + FieldValue.zext(8); } - void ConvertStructToPacked() { - std::vector PackedElements; - uint64_t ElementOffsetInBytes = 0; + // Append the last element. + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), + FieldValue)); + NextFieldOffsetInBytes++; + return true; +} - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - llvm::Constant *C = Elements[i]; +void ConstStructBuilder::AppendPadding(uint64_t NumBytes) { + if (!NumBytes) + return; - unsigned ElementAlign = - CGM.getTargetData().getABITypeAlignment(C->getType()); - uint64_t AlignedElementOffsetInBytes = - llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { - // We need some padding. - uint64_t NumBytes = - AlignedElementOffsetInBytes - ElementOffsetInBytes; + llvm::Constant *C = llvm::UndefValue::get(Ty); + Elements.push_back(C); + assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + NextFieldOffsetInBytes += getSizeInBytes(C); +} - llvm::Constant *Padding = llvm::UndefValue::get(Ty); - PackedElements.push_back(Padding); - ElementOffsetInBytes += getSizeInBytes(Padding); - } +void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) { + assert(RecordSize % 8 == 0 && "Invalid record size!"); - PackedElements.push_back(C); - ElementOffsetInBytes += getSizeInBytes(C); - } + uint64_t RecordSizeInBytes = RecordSize / 8; + assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); - assert(ElementOffsetInBytes == NextFieldOffsetInBytes && - "Packing the struct changed its size!"); + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + AppendPadding(NumPadBytes); +} - Elements = PackedElements; - LLVMStructAlignment = 1; - Packed = true; - } - - bool Build(InitListExpr *ILE) { - RecordDecl *RD = ILE->getType()->getAs()->getDecl(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - - unsigned FieldNo = 0; - unsigned ElementNo = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - ElementNo < ILE->getNumInits() && Field != FieldEnd; - ++Field, ++FieldNo) { - if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) - continue; - - if (Field->isBitField()) { - if (!Field->getIdentifier()) - continue; - - if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } else { - if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } +void ConstStructBuilder::ConvertStructToPacked() { + std::vector PackedElements; + uint64_t ElementOffsetInBytes = 0; - ElementNo++; - } + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + llvm::Constant *C = Elements[i]; - uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + unsigned ElementAlign = + CGM.getTargetData().getABITypeAlignment(C->getType()); + uint64_t AlignedElementOffsetInBytes = + llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); - if (NextFieldOffsetInBytes > LayoutSizeInBytes) { - // If the struct is bigger than the size of the record type, - // we must have a flexible array member at the end. - assert(RD->hasFlexibleArrayMember() && - "Must have flexible array member if struct is bigger than type!"); - - // No tail padding is necessary. - return true; - } + if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { + // We need some padding. + uint64_t NumBytes = + AlignedElementOffsetInBytes - ElementOffsetInBytes; - uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, - LLVMStructAlignment); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - // Check if we need to convert the struct to a packed struct. - if (NextFieldOffsetInBytes <= LayoutSizeInBytes && - LLVMSizeInBytes > LayoutSizeInBytes) { - assert(!Packed && "Size mismatch!"); - - ConvertStructToPacked(); - assert(NextFieldOffsetInBytes == LayoutSizeInBytes && - "Converting to packed did not help!"); + llvm::Constant *Padding = llvm::UndefValue::get(Ty); + PackedElements.push_back(Padding); + ElementOffsetInBytes += getSizeInBytes(Padding); } - // Append tail padding if necessary. - AppendTailPadding(Layout.getSize()); - - assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && - "Tail padding mismatch!"); - - return true; + PackedElements.push_back(C); + ElementOffsetInBytes += getSizeInBytes(C); } - unsigned getAlignment(const llvm::Constant *C) const { - if (Packed) - return 1; + assert(ElementOffsetInBytes == NextFieldOffsetInBytes && + "Packing the struct changed its size!"); - return CGM.getTargetData().getABITypeAlignment(C->getType()); + Elements = PackedElements; + LLVMStructAlignment = 1; + Packed = true; +} + +bool ConstStructBuilder::Build(InitListExpr *ILE) { + RecordDecl *RD = ILE->getType()->getAs()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + unsigned FieldNo = 0; + unsigned ElementNo = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isBitField() && !Field->getIdentifier()) + continue; + + // Get the initializer. A struct can include fields without initializers, + // we just use explicit null values for them. + llvm::Constant *EltInit; + if (ElementNo < ILE->getNumInits()) + EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++), + Field->getType(), CGF); + else + EltInit = CGM.EmitNullConstant(Field->getType()); + + if (!Field->isBitField()) { + // Handle non-bitfield members. + if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) + return false; + } else { + // Otherwise we have a bitfield. + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) + return false; + } } - uint64_t getSizeInBytes(const llvm::Constant *C) const { - return CGM.getTargetData().getTypeAllocSize(C->getType()); + uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + + if (NextFieldOffsetInBytes > LayoutSizeInBytes) { + // If the struct is bigger than the size of the record type, + // we must have a flexible array member at the end. + assert(RD->hasFlexibleArrayMember() && + "Must have flexible array member if struct is bigger than type!"); + + // No tail padding is necessary. + return true; } -public: - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, - InitListExpr *ILE) { - ConstStructBuilder Builder(CGM, CGF); + uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, + LLVMStructAlignment); - if (!Builder.Build(ILE)) - return 0; + // Check if we need to convert the struct to a packed struct. + if (NextFieldOffsetInBytes <= LayoutSizeInBytes && + LLVMSizeInBytes > LayoutSizeInBytes) { + assert(!Packed && "Size mismatch!"); + + ConvertStructToPacked(); + assert(NextFieldOffsetInBytes <= LayoutSizeInBytes && + "Converting to packed did not help!"); + } - llvm::Constant *Result = - llvm::ConstantStruct::get(CGM.getLLVMContext(), - Builder.Elements, Builder.Packed); + // Append tail padding if necessary. + AppendTailPadding(Layout.getSize()); - assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, - Builder.getAlignment(Result)) == - Builder.getSizeInBytes(Result) && "Size mismatch!"); + assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && + "Tail padding mismatch!"); - return Result; - } -}; + return true; +} + +llvm::Constant *ConstStructBuilder:: + BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) { + ConstStructBuilder Builder(CGM, CGF); + + if (!Builder.Build(ILE)) + return 0; + + llvm::Constant *Result = + llvm::ConstantStruct::get(CGM.getLLVMContext(), + Builder.Elements, Builder.Packed); + + assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, + Builder.getAlignment(Result)) == + Builder.getSizeInBytes(Result) && "Size mismatch!"); + + return Result; +} + +//===----------------------------------------------------------------------===// +// ConstExprEmitter +//===----------------------------------------------------------------------===// + class ConstExprEmitter : public StmtVisitor { CodeGenModule &CGM; @@ -418,13 +446,18 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { - uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD); + uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGM.getContext().Target.getPointerWidth(0) / 8; + // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. // For a virtual function, it is 1 plus the virtual table offset // (in bytes) of the function, represented as a ptrdiff_t. - Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); + Values[0] = llvm::ConstantInt::get(PtrDiffTy, + (Index * PointerWidthInBytes) + 1); } else { const FunctionProtoType *FPT = MD->getType()->getAs(); const llvm::Type *Ty = @@ -528,8 +561,6 @@ public: const MemberPointerType *DestTy = E->getType()->getAs(); - const CXXRecordDecl *BaseClass = - cast(cast(SrcTy->getClass())->getDecl()); const CXXRecordDecl *DerivedClass = cast(cast(DestTy->getClass())->getDecl()); @@ -543,7 +574,7 @@ public: // Check if we need to update the adjustment. if (llvm::Constant *Offset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) { + CGM.GetNonVirtualBaseClassOffset(DerivedClass, E->getBasePath())) { llvm::Constant *Values[2]; Values[0] = CS->getOperand(0); @@ -587,17 +618,15 @@ public: } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { - std::vector Elts; - const llvm::ArrayType *AType = - cast(ConvertType(ILE->getType())); unsigned NumInitElements = ILE->getNumInits(); - // FIXME: Check for wide strings - // FIXME: Check for NumInitElements exactly equal to 1?? - if (NumInitElements > 0 && + if (NumInitElements == 1 && (isa(ILE->getInit(0)) || - isa(ILE->getInit(0))) && - ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType()) + isa(ILE->getInit(0)))) return Visit(ILE->getInit(0)); + + std::vector Elts; + const llvm::ArrayType *AType = + cast(ConvertType(ILE->getType())); const llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d1c0f8d..9849688 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -133,6 +133,7 @@ public: CGF.getContext().typesAreCompatible( E->getArgType1(), E->getArgType2())); } + Value *VisitOffsetOfExpr(const OffsetOfExpr *E); Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); @@ -242,7 +243,7 @@ public: return Visit(E->getSubExpr()); } Value *VisitUnaryOffsetOf(const UnaryOperator *E); - + // C++ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); @@ -314,6 +315,10 @@ public: } BinOpInfo EmitBinOps(const BinaryOperator *E); + LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*F)(const BinOpInfo &), + Value *&BitFieldResult); + Value *EmitCompoundAssign(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*F)(const BinOpInfo &)); @@ -818,16 +823,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return Visit(const_cast(E)); case CastExpr::CK_BaseToDerived: { - const CXXRecordDecl *BaseClassDecl = - E->getType()->getCXXRecordDeclForPointerType(); const CXXRecordDecl *DerivedClassDecl = DestTy->getCXXRecordDeclForPointerType(); - Value *Src = Visit(const_cast(E)); - - bool NullCheckValue = ShouldNullCheckClassCastValue(CE); - return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl, - NullCheckValue); + return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, + CE->getBasePath(), + ShouldNullCheckClassCastValue(CE)); } case CastExpr::CK_UncheckedDerivedToBase: case CastExpr::CK_DerivedToBase: { @@ -836,15 +837,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); - const RecordType *BaseClassTy = - DestTy->getAs()->getPointeeType()->getAs(); - CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); - - Value *Src = Visit(const_cast(E)); - - bool NullCheckValue = ShouldNullCheckClassCastValue(CE); - return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, - NullCheckValue); + return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl, + CE->getBasePath(), + ShouldNullCheckClassCastValue(CE)); } case CastExpr::CK_Dynamic: { Value *V = Visit(const_cast(E)); @@ -894,7 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { std::swap(DerivedDecl, BaseDecl); if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, + CE->getBasePath())) { if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) Src = Builder.CreateSub(Src, Adj, "adj"); else @@ -1035,6 +1031,21 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext"); } +Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) { + Expr::EvalResult Result; + if(E->Evaluate(Result, CGF.getContext())) + return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + + // FIXME: Cannot support code generation for non-constant offsetof. + unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error, + "cannot compile non-constant __builtin_offsetof"); + CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()), + DiagID) + << E->getSourceRange(); + + return llvm::Constant::getNullValue(ConvertType(E->getType())); +} + /// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of /// argument of the sizeof expression as an integer. Value * @@ -1103,22 +1114,24 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { return Result; } -Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, - Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { - bool Ignore = TestAndClearIgnoreResultAssign(); +LValue ScalarExprEmitter::EmitCompoundAssignLValue( + const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &), + Value *&BitFieldResult) { QualType LHSTy = E->getLHS()->getType(); - + BitFieldResult = 0; BinOpInfo OpInfo; - + if (E->getComputationResultType()->isAnyComplexType()) { // This needs to go through the complex expression emitter, but it's a tad // complicated to do that... I'm leaving it out for now. (Note that we do // actually need the imaginary part of the RHS for multiplication and // division.) CGF.ErrorUnsupported(E, "complex compound assignment"); - return llvm::UndefValue::get(CGF.ConvertType(E->getType())); + llvm::UndefValue::get(CGF.ConvertType(E->getType())); + return LValue(); } - + // Emit the RHS first. __block variables need to have the rhs evaluated // first, plus this should improve codegen a little. OpInfo.RHS = Visit(E->getRHS()); @@ -1129,13 +1142,13 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType()); - + // Expand the binary operator. Value *Result = (this->*Func)(OpInfo); - + // Convert the result back to the LHS type. Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy); - + // Store the result value into the LHS lvalue. Bit-fields are handled // specially because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after the @@ -1144,11 +1157,23 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, if (!LHSLV.isVolatileQualified()) { CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy, &Result); - return Result; + BitFieldResult = Result; + return LHSLV; } else CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy); } else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy); + return LHSLV; +} + +Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { + bool Ignore = TestAndClearIgnoreResultAssign(); + Value *BitFieldResult; + LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult); + if (BitFieldResult) + return BitFieldResult; + if (Ignore) return 0; return EmitLoadOfLValue(LHSLV, E->getType()); @@ -1914,3 +1939,53 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { return LV; } + +LValue CodeGenFunction::EmitCompoundAssignOperatorLValue( + const CompoundAssignOperator *E) { + ScalarExprEmitter Scalar(*this); + Value *BitFieldResult = 0; + switch (E->getOpcode()) { +#define COMPOUND_OP(Op) \ + case BinaryOperator::Op##Assign: \ + return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \ + BitFieldResult) + COMPOUND_OP(Mul); + COMPOUND_OP(Div); + COMPOUND_OP(Rem); + COMPOUND_OP(Add); + COMPOUND_OP(Sub); + COMPOUND_OP(Shl); + COMPOUND_OP(Shr); + COMPOUND_OP(And); + COMPOUND_OP(Xor); + COMPOUND_OP(Or); +#undef COMPOUND_OP + + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::Assign: + case BinaryOperator::Comma: + assert(false && "Not valid compound assignment operators"); + break; + } + + llvm_unreachable("Unhandled compound assignment operator"); +} diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 206d438..3359250 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -53,31 +53,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { // arguments in generic code. CGObjCRuntime &Runtime = CGM.getObjCRuntime(); - const Expr *ReceiverExpr = E->getReceiver(); bool isSuperMessage = false; bool isClassMessage = false; + ObjCInterfaceDecl *OID = 0; // Find the receiver - llvm::Value *Receiver; - if (!ReceiverExpr) { - const ObjCInterfaceDecl *OID = E->getClassInfo().Decl; - - // Very special case, super send in class method. The receiver is - // self (the class object) and the send uses super semantics. - if (!OID) { - assert(E->getClassName()->isStr("super") && - "Unexpected missing class interface in message send."); - isSuperMessage = true; - Receiver = LoadObjCSelf(); - } else { - Receiver = Runtime.GetClass(Builder, OID); - } - + llvm::Value *Receiver = 0; + switch (E->getReceiverKind()) { + case ObjCMessageExpr::Instance: + Receiver = EmitScalarExpr(E->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: { + const ObjCInterfaceType *IFace + = E->getClassReceiver()->getAs(); + OID = IFace->getDecl(); + assert(IFace && "Invalid Objective-C class message send"); + Receiver = Runtime.GetClass(Builder, OID); isClassMessage = true; - } else if (isa(E->getReceiver())) { + break; + } + + case ObjCMessageExpr::SuperInstance: + Receiver = LoadObjCSelf(); isSuperMessage = true; + break; + + case ObjCMessageExpr::SuperClass: Receiver = LoadObjCSelf(); - } else { - Receiver = EmitScalarExpr(E->getReceiver()); + isSuperMessage = true; + isClassMessage = true; + break; } CallArgList Args; @@ -98,7 +103,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { } return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), - Receiver, isClassMessage, Args, + Receiver, Args, OID, E->getMethodDecl()); } @@ -148,19 +153,21 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); const ObjCPropertyDecl *PD = PID->getPropertyDecl(); + bool IsAtomic = + !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); // FIXME: This is rather murky, we create this here since they will not have // been created by Sema for us. OMD->createImplicitParams(getContext(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); - + // Determine if we should use an objc_getProperty call for // this. Non-atomic properties are directly evaluated. // atomic 'copy' and 'retain' properties are also directly // evaluated in gc-only mode. if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly && - !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) && + IsAtomic && (PD->getSetterKind() == ObjCPropertyDecl::Copy || PD->getSetterKind() == ObjCPropertyDecl::Retain)) { llvm::Value *GetPropertyFn = @@ -208,7 +215,44 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); } else if (hasAggregateLLVMType(Ivar->getType())) { - EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); + bool IsStrong = false; + if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType()))) + && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect + && CGM.getObjCRuntime().GetCopyStructFunction()) { + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + // objc_copyStruct (ReturnValue, &structIvar, + // sizeof (Type of Ivar), isAtomic, false); + CallArgList Args; + RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *isAtomic = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), + IsAtomic ? 1 : 0); + Args.push_back(std::make_pair(RValue::get(isAtomic), + getContext().BoolTy)); + llvm::Value *hasStrong = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), + IsStrong ? 1 : 0); + Args.push_back(std::make_pair(RValue::get(hasStrong), + getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); + } + else + EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); } else { CodeGenTypes &Types = CGM.getTypes(); RValue RV = EmitLoadOfLValue(LV, Ivar->getType()); @@ -289,6 +333,41 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FunctionType::ExtInfo()), SetPropertyFn, ReturnValueSlot(), Args); + } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) && + !Ivar->getType()->isAnyComplexType() && + IndirectObjCSetterArg(*CurFnInfo) + && CGM.getObjCRuntime().GetCopyStructFunction()) { + // objc_copyStruct (&structIvar, &Arg, + // sizeof (struct something), true, false); + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + CallArgList Args; + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); + RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; + llvm::Value *ArgAsPtrTy = + Builder.CreateBitCast(Arg, + Types.ConvertType(getContext().VoidPtrTy)); + RV = RValue::get(ArgAsPtrTy); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *True = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); + Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); + llvm::Value *False = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); + Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -304,7 +383,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, if (getContext().getCanonicalType(Ivar->getType()) != getContext().getCanonicalType(ArgDecl->getType())) { ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg, - false); + CXXBaseSpecifierArray(), false); BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign, Ivar->getType(), Loc); EmitStmt(&Assign); @@ -318,6 +397,83 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FinishFunction(); } +void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, + ObjCMethodDecl *MD, + bool ctor) { + llvm::SmallVector IvarInitializers; + MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface()); + StartObjCMethod(MD, IMP->getClassInterface()); + for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(), + E = IMP->init_end(); B != E; ++B) { + CXXBaseOrMemberInitializer *Member = (*B); + IvarInitializers.push_back(Member); + } + if (ctor) { + for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) { + CXXBaseOrMemberInitializer *IvarInit = IvarInitializers[I]; + FieldDecl *Field = IvarInit->getMember(); + QualType FieldType = Field->getType(); + ObjCIvarDecl *Ivar = cast(Field); + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), + LoadObjCSelf(), Ivar, 0); + EmitAggExpr(IvarInit->getInit(), LV.getAddress(), + LV.isVolatileQualified(), false, true); + } + // constructor returns 'self'. + CodeGenTypes &Types = CGM.getTypes(); + QualType IdTy(CGM.getContext().getObjCIdType()); + llvm::Value *SelfAsId = + Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); + EmitReturnOfRValue(RValue::get(SelfAsId), IdTy); + } + else { + // dtor + for (size_t i = IvarInitializers.size(); i > 0; --i) { + FieldDecl *Field = IvarInitializers[i - 1]->getMember(); + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + ObjCIvarDecl *Ivar = cast(Field); + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), + LoadObjCSelf(), Ivar, 0); + const RecordType *RT = FieldType->getAs(); + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LV.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(CGM.getContext()), + Dtor_Complete, /*ForVirtualBase=*/false, + LV.getAddress()); + } + } + FinishFunction(); +} + +bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) { + CGFunctionInfo::const_arg_iterator it = FI.arg_begin(); + it++; it++; + const ABIArgInfo &AI = it->info; + // FIXME. Is this sufficient check? + return (AI.getKind() == ABIArgInfo::Indirect); +} + +bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { + if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) + return false; + if (const RecordType *FDTTy = Ty.getTypePtr()->getAs()) + return FDTTy->getDecl()->hasObjectMember(); + return false; +} + llvm::Value *CodeGenFunction::LoadObjCSelf() { const ObjCMethodDecl *OMD = cast(CurFuncDecl); // See if we need to lazily forward self inside a block literal. @@ -360,7 +516,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { return CGM.getObjCRuntime(). GenerateMessageSend(*this, Exp->getType(), S, EmitScalarExpr(E->getBase()), - false, CallArgList()); + CallArgList()); } else { const ObjCImplicitSetterGetterRefExpr *KE = cast(Exp); @@ -376,7 +532,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { return CGM.getObjCRuntime(). GenerateMessageSend(*this, Exp->getType(), S, Receiver, - KE->getInterfaceDecl() != 0, CallArgList()); + CallArgList(), KE->getInterfaceDecl()); } } @@ -413,7 +569,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, E->getType())); CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, EmitScalarExpr(E->getBase()), - false, Args); + Args); } else if (const ObjCImplicitSetterGetterRefExpr *E = dyn_cast(Exp)) { Selector S = E->getSetterMethod()->getSelector(); @@ -430,7 +586,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, E->getType())); CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, Receiver, - E->getInterfaceDecl() != 0, Args); + Args, E->getInterfaceDecl()); } else assert (0 && "bad expression node in EmitObjCPropertySet"); } @@ -498,7 +654,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, - Collection, false, Args); + Collection, Args); llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy, "limit.ptr"); @@ -623,7 +779,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, - Collection, false, Args); + Collection, Args); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); Limit = Builder.CreateLoad(LimitPtr); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index d445200..3c51b7e 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -26,6 +26,7 @@ #include "llvm/Intrinsics.h" #include "llvm/Module.h" +#include "llvm/LLVMContext.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Compiler.h" @@ -81,6 +82,8 @@ private: llvm::Constant *Zeros[2]; llvm::Constant *NULLPtr; llvm::LLVMContext &VMContext; + /// Metadata kind used to tie method lookups to message sends. + unsigned msgSendMDKind; private: llvm::Constant *GenerateIvarList( const llvm::SmallVectorImpl &IvarNames, @@ -112,7 +115,8 @@ private: llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, - llvm::Constant *Properties); + llvm::Constant *Properties, + bool isMeta=false); llvm::Constant *GenerateProtocolMethodList( const llvm::SmallVectorImpl &MethodNames, const llvm::SmallVectorImpl &MethodTypes); @@ -141,8 +145,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, @@ -170,6 +174,7 @@ public: virtual llvm::Function *ModuleInitFunction(); virtual llvm::Function *GetPropertyGetFunction(); virtual llvm::Function *GetPropertySetFunction(); + virtual llvm::Function *GetCopyStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -221,10 +226,6 @@ void CGObjCGNU::EmitClassRef(const std::string &className) { llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } -static std::string SymbolNameForClass(const std::string &ClassName) { - return "_OBJC_CLASS_" + ClassName; -} - static std::string SymbolNameForMethod(const std::string &ClassName, const std::string &CategoryName, const std::string &MethodName, bool isClassMethod) { @@ -238,6 +239,9 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0), MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) { + + msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); + IntTy = cast( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); LongTy = cast( @@ -452,12 +456,15 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, return RValue::get(0); } } - llvm::Value *cmd = GetSelector(CGF.Builder, Sel); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *cmd = GetSelector(Builder, Sel); + CallArgList ActualArgs; ActualArgs.push_back( - std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), + std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)), ASTIdTy)); ActualArgs.push_back(std::make_pair(RValue::get(cmd), CGF.getContext().getObjCSelType())); @@ -481,7 +488,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, Params, true), "objc_get_class"); } - ReceiverClass = CGF.Builder.CreateCall(classLookupFunction, + ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); } else { // Set up global aliases for the metaclass or class pointer if they do not @@ -506,36 +513,64 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } } // Cast the pointer to a simplified version of the class structure - ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass, + ReceiverClass = Builder.CreateBitCast(ReceiverClass, llvm::PointerType::getUnqual( llvm::StructType::get(VMContext, IdTy, IdTy, NULL))); // Get the superclass pointer - ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1); + ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1); // Load the superclass pointer - ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass); + ReceiverClass = Builder.CreateLoad(ReceiverClass); // Construct the structure used to look up the IMP llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext, Receiver->getType(), IdTy, NULL); - llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy); + llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy); - CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0)); - CGF.Builder.CreateStore(ReceiverClass, - CGF.Builder.CreateStructGEP(ObjCSuper, 1)); + Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0)); + Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); // Get the IMP std::vector Params; Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy)); Params.push_back(SelectorTy); + + llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; + llvm::Value *imp; + + if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { + // The lookup function returns a slot, which can be safely cached. + llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy, + IntTy, llvm::PointerType::getUnqual(impType), NULL); + + llvm::Constant *lookupFunction = + CGM.CreateRuntimeFunction(llvm::FunctionType::get( + llvm::PointerType::getUnqual(SlotTy), Params, true), + "objc_slot_lookup_super"); + + llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs, + lookupArgs+2); + slot->setOnlyReadsMemory(); + + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + } else { llvm::Constant *lookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::PointerType::getUnqual(impType), Params, true), "objc_msg_lookup_super"); + imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2); + } - llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; - llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs, - lookupArgs+2); - - return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + + llvm::Instruction *call; + RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + 0, &call); + call->setMetadata(msgSendMDKind, node); + return msgRet; } /// Generate code for a message send expression. @@ -544,9 +579,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { + // Strip out message sends to retain / release in GC mode if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(Receiver); @@ -555,7 +591,39 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, return RValue::get(0); } } + CGBuilderTy &Builder = CGF.Builder; + + // If the return type is something that goes in an integer register, the + // runtime will handle 0 returns. For other cases, we fill in the 0 value + // ourselves. + // + // The language spec says the result of this kind of message send is + // undefined, but lots of people seem to have forgotten to read that + // paragraph and insist on sending messages to nil that have structure + // returns. With GCC, this generates a random return value (whatever happens + // to be on the stack / in those registers at the time) on most platforms, + // and generates a SegV on SPARC. With LLVM it corrupts the stack. + bool isPointerSizedReturn = false; + if (ResultType->isAnyPointerType() || ResultType->isIntegralType() || + ResultType->isVoidType()) + isPointerSizedReturn = true; + + llvm::BasicBlock *startBB = 0; + llvm::BasicBlock *messageBB = 0; + llvm::BasicBlock *contiueBB = 0; + + if (!isPointerSizedReturn) { + startBB = Builder.GetInsertBlock(); + messageBB = CGF.createBasicBlock("msgSend"); + contiueBB = CGF.createBasicBlock("continue"); + + llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, + llvm::Constant::getNullValue(Receiver->getType())); + Builder.CreateCondBr(isNil, contiueBB, messageBB); + CGF.EmitBlock(messageBB); + } + IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) @@ -577,6 +645,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + + llvm::Value *imp; // For sender-aware dispatch, we pass the sender as the third argument to a // lookup function. When sending messages from C code, the sender is nil. @@ -611,9 +687,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, LookupFn->setDoesNotCapture(1); } - llvm::Value *slot = + llvm::CallInst *slot = Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self); + slot->setOnlyReadsMemory(); + slot->setMetadata(msgSendMDKind, node); + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + // The lookup function may have changed the receiver, so make sure we use // the new one. ActualArgs[0] = @@ -628,9 +708,46 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, "objc_msg_lookup"); imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); + cast(imp)->setMetadata(msgSendMDKind, node); } - - return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); + llvm::Instruction *call; + RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + 0, &call); + call->setMetadata(msgSendMDKind, node); + + if (!isPointerSizedReturn) { + CGF.EmitBlock(contiueBB); + if (msgRet.isScalar()) { + llvm::Value *v = msgRet.getScalarVal(); + llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + phi->addIncoming(v, messageBB); + phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); + msgRet = RValue::get(phi); + } else if (msgRet.isAggregate()) { + llvm::Value *v = msgRet.getAggregateAddr(); + llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + const llvm::PointerType *RetTy = cast(v->getType()); + llvm::AllocaInst *NullVal = + CGF.CreateTempAlloca(RetTy->getElementType(), "null"); + CGF.InitTempAlloca(NullVal, + llvm::Constant::getNullValue(RetTy->getElementType())); + phi->addIncoming(v, messageBB); + phi->addIncoming(NullVal, startBB); + msgRet = RValue::getAggregate(phi); + } else /* isComplex() */ { + std::pair v = msgRet.getComplexVal(); + llvm::PHINode *phi = Builder.CreatePHI(v.first->getType()); + phi->addIncoming(v.first, messageBB); + phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), + startBB); + llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType()); + phi2->addIncoming(v.second, messageBB); + phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), + startBB); + msgRet = RValue::getComplex(phi, phi2); + } + } + return msgRet; } /// Generates a MethodList. Used in construction of a objc_class and @@ -749,7 +866,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, - llvm::Constant *Properties) { + llvm::Constant *Properties, + bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is // because the runtime performs this translation on load. @@ -799,8 +917,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. - return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name), - llvm::GlobalValue::ExternalLinkage); + return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_": + "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage); } llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( @@ -1289,16 +1407,21 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { instanceSize = 0 - (instanceSize - superInstanceSize); } - for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(), - endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) { + + // Collect declared and synthesized ivars. + llvm::SmallVector OIvars; + CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars); + + for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { + ObjCIvarDecl *IVD = OIvars[i]; // Store the name - IvarNames.push_back(MakeConstantString((*iter)->getNameAsString())); + IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); // Get the type encoding for this ivar std::string TypeStr; - Context.getObjCEncodingForType((*iter)->getType(), TypeStr); + Context.getObjCEncodingForType(IVD->getType(), TypeStr); IvarTypes.push_back(MakeConstantString(TypeStr)); // Get the offset - uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter); + uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { Offset = BaseOffset - superInstanceSize; @@ -1309,7 +1432,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(IntTy, BaseOffset), "__objc_ivar_offset_value_" + ClassName +"." + - (*iter)->getNameAsString())); + IVD->getNameAsString())); } llvm::Constant *IvarOffsetArrayInit = llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy, @@ -1411,7 +1534,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( - empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr); + empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true); // Generate the class structure llvm::Constant *ClassStruct = @@ -1658,10 +1781,9 @@ llvm::Function *CGObjCGNU::GetPropertyGetFunction() { CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Params.push_back(IdTy); Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); + Params.push_back(IntTy); Params.push_back(BoolTy); - // void objc_getProperty (id, SEL, ptrdiff_t, bool) + // void objc_getProperty (id, SEL, int, bool) const llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Params, false); return cast(CGM.CreateRuntimeFunction(FTy, @@ -1674,18 +1796,22 @@ llvm::Function *CGObjCGNU::GetPropertySetFunction() { CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Params.push_back(IdTy); Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); + Params.push_back(IntTy); Params.push_back(IdTy); Params.push_back(BoolTy); Params.push_back(BoolTy); - // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) + // void objc_setProperty (id, SEL, int, id, bool, bool) const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); return cast(CGM.CreateRuntimeFunction(FTy, "objc_setProperty")); } +// FIXME. Implement this. +llvm::Function *CGObjCGNU::GetCopyStructFunction() { + return 0; +} + llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -1764,7 +1890,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow"); llvm::SmallVector ESelArgs; - llvm::SmallVector, 8> Handlers; + llvm::SmallVector, 8> Handlers; ESelArgs.push_back(Exc); ESelArgs.push_back(Personality); @@ -1772,12 +1898,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, bool HasCatchAll = false; // Only @try blocks are allowed @catch blocks, but both can have @finally if (isTry) { - if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) { + if (cast(S).getNumCatchStmts()) { + const ObjCAtTryStmt &AtTry = cast(S); CGF.setInvokeDest(CatchInCatch); - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { - const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); @@ -1816,7 +1943,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ESelArgs.begin(), ESelArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - const ParmVarDecl *CatchParam = Handlers[i].first; + const VarDecl *CatchParam = Handlers[i].first; const Stmt *CatchBody = Handlers[i].second; llvm::BasicBlock *Next = 0; @@ -2046,7 +2173,14 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( // when linked against code which isn't (most of the time). llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); if (!IvarOffsetPointer) { - uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); + uint64_t Offset; + if (ObjCImplementationDecl *OID = + CGM.getContext().getObjCImplementation( + const_cast(ID))) + Offset = ComputeIvarBaseOffset(CGM, OID, Ivar); + else + Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); + llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar"); // Don't emit the guess in non-PIC code because the linker will not be able diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index ac8fa05..77eabbf 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -124,9 +124,19 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // layout object. However, this is blocked on other cleanups to the // Objective-C code, so for now we just live with allocating a bunch of these // objects. - unsigned FieldNo = 0; // This value is unused. + + // We always construct a single, possibly unaligned, access for this case. + CGBitFieldInfo::AccessInfo AI; + AI.FieldIndex = 0; + AI.FieldByteOffset = 0; + AI.FieldBitStart = BitOffset; + AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy); + AI.AccessAlignment = 0; + AI.TargetBitOffset = 0; + AI.TargetBitWidth = BitFieldSize; + CGBitFieldInfo *Info = - new (CGF.CGM.getContext()) CGBitFieldInfo(FieldNo, BitOffset, BitFieldSize, + new (CGF.CGM.getContext()) CGBitFieldInfo(BitFieldSize, 1, &AI, IvarTy->isSignedIntegerType()); // FIXME: We need to set a very conservative alignment on this, or make sure @@ -329,6 +339,24 @@ public: return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } + + llvm::Constant *getCopyStructFn() { + CodeGen::CodeGenTypes &Types = CGM.getTypes(); + ASTContext &Ctx = CGM.getContext(); + // void objc_copyStruct (void *, const void *, size_t, bool, bool) + llvm::SmallVector Params; + Params.push_back(Ctx.VoidPtrTy); + Params.push_back(Ctx.VoidPtrTy); + Params.push_back(Ctx.LongTy); + Params.push_back(Ctx.BoolTy); + Params.push_back(Ctx.BoolTy); + const llvm::FunctionType *FTy = + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + FunctionType::ExtInfo()), + false); + return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct"); + } + llvm::Constant *getEnumerationMutationFn() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -954,6 +982,10 @@ protected: const ObjCMethodDecl *OMD, const ObjCCommonTypesHelper &ObjCTypes); + /// EmitImageInfo - Emit the image info marker used to encode some module + /// level information. + void EmitImageInfo(); + public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getLLVMContext()) { } @@ -980,9 +1012,6 @@ public: class CGObjCMac : public CGObjCCommonMac { private: ObjCTypesHelper ObjCTypes; - /// EmitImageInfo - Emit the image info marker used to encode some module - /// level information. - void EmitImageInfo(); /// EmitModuleInfo - Another marker encoding module level /// information. @@ -1100,8 +1129,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue @@ -1134,6 +1163,7 @@ public: virtual llvm::Constant *GetPropertyGetFunction(); virtual llvm::Constant *GetPropertySetFunction(); + virtual llvm::Constant *GetCopyStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -1327,8 +1357,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue @@ -1366,6 +1396,11 @@ public: virtual llvm::Constant *GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } + + virtual llvm::Constant *GetCopyStructFunction() { + return ObjCTypes.getCopyStructFn(); + } + virtual llvm::Constant *EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } @@ -1459,9 +1494,20 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl }; */ +/// or Generate a constant NSString object. +/* + struct __builtin_NSString { + const int *isa; // point to __NSConstantStringClassReference + const char *str; + unsigned int length; + }; +*/ + llvm::Constant *CGObjCCommonMac::GenerateConstantString( const StringLiteral *SL) { - return CGM.GetAddrOfConstantCFString(SL); + return (CGM.getLangOptions().NoConstantCFStrings == 0 ? + CGM.GetAddrOfConstantCFString(SL) : + CGM.GetAddrOfConstantNSString(SL)); } /// Generates a message send where the super is the receiver. This is @@ -1531,8 +1577,8 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), @@ -1696,7 +1742,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { Init, "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } @@ -1718,7 +1763,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { 0, "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } @@ -2039,6 +2083,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Interface->protocol_begin(), Interface->protocol_end()); unsigned Flags = eClassFlags_Factory; + if (ID->getNumIvarInitializers()) + Flags |= eClassFlags_HasCXXStructors; unsigned Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8; @@ -2430,6 +2476,10 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } +llvm::Constant *CGObjCMac::GetCopyStructFunction() { + return ObjCTypes.getCopyStructFn(); +} + llvm::Constant *CGObjCMac::EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } @@ -2597,8 +2647,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), CallTryExitPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); - } else if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) { + } else if (cast(S).getNumCatchStmts()) { + const ObjCAtTryStmt* AtTryStmt = cast(&S); + // Enter a new exception try block (in case a @catch block throws // an exception). CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData); @@ -2617,10 +2668,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // matched and avoid generating code for falling off the end if // so. bool AllMatched = false; - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { + for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I); llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch"); - const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl(); + const VarDecl *CatchParam = CatchStmt->getCatchParamDecl(); const ObjCObjectPointerType *OPT = 0; // catch(...) always matches. @@ -2911,18 +2963,17 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, /// unsigned flags; /// }; enum ImageInfoFlags { - eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what - // this implies. + eImageInfo_FixAndContinue = (1 << 0), eImageInfo_GarbageCollected = (1 << 1), eImageInfo_GCOnly = (1 << 2), eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set. - // A flag indicating that the module has no instances of an - // @synthesize of a superclass variable. + // A flag indicating that the module has no instances of a @synthesize of a + // superclass variable. eImageInfo_CorrectedSynthesize = (1 << 4) }; -void CGObjCMac::EmitImageInfo() { +void CGObjCCommonMac::EmitImageInfo() { unsigned version = 0; // Version is unused? unsigned flags = 0; @@ -3132,19 +3183,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, FieldDecl *Field = RecFields[i]; uint64_t FieldOffset; if (RD) { - const CGRecordLayout &RL = - CGM.getTypes().getCGRecordLayout(Field->getParent()); - if (Field->isBitField()) { - const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - - const llvm::Type *Ty = - CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); - uint64_t TypeSize = - CGM.getTypes().getTargetData().getTypeAllocSize(Ty); - FieldOffset = Info.FieldNo * TypeSize; - } else - FieldOffset = - Layout->getElementOffset(RL.getLLVMFieldNo(Field)); + // Note that 'i' here is actually the field index inside RD of Field, + // although this dependency is hidden. + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + FieldOffset = RL.getFieldOffset(i) / 8; } else FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast(Field)); @@ -3536,7 +3578,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = dyn_cast(D->getDeclContext())) - OS << '(' << CID->getNameAsString() << ')'; + OS << '(' << CID << ')'; OS << ' ' << D->getSelector().getAsString() << ']'; } @@ -3574,14 +3616,14 @@ void CGObjCMac::FinishModule() { Asm += '\n'; llvm::raw_svector_ostream OS(Asm); - for (llvm::SetVector::iterator I = LazySymbols.begin(), - e = LazySymbols.end(); I != e; ++I) - OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; for (llvm::SetVector::iterator I = DefinedSymbols.begin(), e = DefinedSymbols.end(); I != e; ++I) OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n" << "\t.globl .objc_class_name_" << (*I)->getName() << "\n"; - + for (llvm::SetVector::iterator I = LazySymbols.begin(), + e = LazySymbols.end(); I != e; ++I) + OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; + CGM.getModule().setModuleInlineAsm(OS.str()); } } @@ -3627,7 +3669,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // id self; // Class cls; // } - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, @@ -4088,7 +4131,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // }; // First the clang type for struct _message_ref_t - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, @@ -4162,7 +4206,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(const llvm::GlobalValue::InternalLinkage, Init, SymbolName); - GV->setAlignment(8); + GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection(SectionName); CGM.AddUsedGlobal(GV); } @@ -4203,28 +4247,7 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { "\01L_OBJC_LABEL_NONLAZY_CATEGORY_$", "__DATA, __objc_nlcatlist, regular, no_dead_strip"); - // static int L_OBJC_IMAGE_INFO[2] = { 0, flags }; - // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0 - std::vector Values(2); - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, 0); - unsigned int flags = 0; - // FIXME: Fix and continue? - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) - flags |= eImageInfo_GarbageCollected; - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) - flags |= eImageInfo_GCOnly; - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); - llvm::Constant* Init = llvm::ConstantArray::get( - llvm::ArrayType::get(ObjCTypes.IntTy, 2), - Values); - llvm::GlobalVariable *IMGV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::InternalLinkage, - Init, - "\01L_OBJC_IMAGE_INFO"); - IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip"); - IMGV->setConstant(true); - CGM.AddUsedGlobal(IMGV); + EmitImageInfo(); } /// LegacyDispatchedSelector - Returns true if SEL is not in the list of @@ -4233,9 +4256,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { /// message dispatch call for all the rest. /// bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { - if (CGM.getCodeGenOpts().ObjCLegacyDispatch) + switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { + default: + assert(0 && "Invalid dispatch method!"); + case CodeGenOptions::Legacy: return true; + case CodeGenOptions::NonLegacy: + return false; + case CodeGenOptions::Mixed: + break; + } + // If so, see whether this selector is in the white-list of things which must + // use the new dispatch convention. We lazily build a dense set for this. if (NonLegacyDispatchMethods.empty()) { NonLegacyDispatchMethods.insert(GetNullarySelector("alloc")); NonLegacyDispatchMethods.insert(GetNullarySelector("class")); @@ -4265,6 +4298,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { NonLegacyDispatchMethods.insert( CGM.getContext().Selectors.getSelector(3, KeyIdents)); } + return (NonLegacyDispatchMethods.count(Sel) == 0); } @@ -4369,7 +4403,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : std::string("\01l_OBJC_CLASS_RO_$_")+ClassName); CLASS_RO_GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy)); CLASS_RO_GV->setSection("__DATA, __objc_const"); return CLASS_RO_GV; @@ -4405,7 +4439,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( GV->setInitializer(Init); GV->setSection("__DATA, __objc_data"); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassnfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy)); if (HiddenVisibility) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return GV; @@ -4467,6 +4501,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; + if (ID->getNumIvarInitializers()) + flags |= eClassFlags_ABI2_HasCXXStructors; if (!ID->getClassInterface()->getSuperClass()) { // class is root flags |= CLS_ROOT; @@ -4501,6 +4537,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { flags = CLS; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; + if (ID->getNumIvarInitializers()) + flags |= eClassFlags_ABI2_HasCXXStructors; if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface())) flags |= CLS_EXCEPTION; @@ -4655,7 +4693,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Init, ExtCatName); GCATV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy)); GCATV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GCATV); DefinedCategories.push_back(GCATV); @@ -4715,7 +4753,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name, Init, Name); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection(Section); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, @@ -4750,7 +4788,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy, Offset)); IvarOffsetGV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy)); // FIXME: This matches gcc, but shouldn't the visibility be set on the use as // well (i.e., in ObjCIvarOffsetVariable). @@ -4837,7 +4875,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( Init, Prefix + OID->getName()); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GV); @@ -4956,7 +4994,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Init, "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); } Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -4969,7 +5007,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Entry, "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName()); PTGV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.AddUsedGlobal(PTGV); @@ -5025,7 +5063,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name, Name); GV->setSection("__DATA, __objc_const"); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); @@ -5184,8 +5222,8 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return LegacyDispatchedSelector(Sel) ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), @@ -5222,7 +5260,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_REFERENCES_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -5245,7 +5283,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -5271,7 +5309,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, MetaClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); @@ -5532,45 +5570,44 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, SelectorArgs.push_back(ObjCTypes.getEHPersonalityPtr()); // Construct the lists of (type, catch body) to handle. - llvm::SmallVector, 8> Handlers; + llvm::SmallVector, 8> Handlers; bool HasCatchAll = false; if (isTry) { - if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) { - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { - const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); - Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); - - // catch(...) always matches. - if (!CatchDecl) { - // Use i8* null here to signal this is a catch all, not a cleanup. - llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); - SelectorArgs.push_back(Null); - HasCatchAll = true; - break; - } + const ObjCAtTryStmt &AtTry = cast(S); + for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); - if (CatchDecl->getType()->isObjCIdType() || - CatchDecl->getType()->isObjCQualifiedIdType()) { - llvm::Value *IDEHType = - CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); - if (!IDEHType) - IDEHType = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, - false, - llvm::GlobalValue::ExternalLinkage, - 0, "OBJC_EHTYPE_id"); - SelectorArgs.push_back(IDEHType); - } else { - // All other types should be Objective-C interface pointer types. - const ObjCObjectPointerType *PT = - CatchDecl->getType()->getAs(); - assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = PT->getInterfaceType(); - assert(IT && "Invalid @catch type."); - llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); - SelectorArgs.push_back(EHType); - } + // catch(...) always matches. + if (!CatchDecl) { + // Use i8* null here to signal this is a catch all, not a cleanup. + llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + SelectorArgs.push_back(Null); + HasCatchAll = true; + break; + } + + if (CatchDecl->getType()->isObjCIdType() || + CatchDecl->getType()->isObjCQualifiedIdType()) { + llvm::Value *IDEHType = + CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); + if (!IDEHType) + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, + false, + llvm::GlobalValue::ExternalLinkage, + 0, "OBJC_EHTYPE_id"); + SelectorArgs.push_back(IDEHType); + } else { + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *PT = + CatchDecl->getType()->getAs(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); + SelectorArgs.push_back(EHType); } } } @@ -5589,7 +5626,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, SelectorArgs.begin(), SelectorArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - const ParmVarDecl *CatchParam = Handlers[i].first; + const VarDecl *CatchParam = Handlers[i].first; const Stmt *CatchBody = Handlers[i].second; llvm::BasicBlock *Next = 0; @@ -5612,14 +5649,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, if (CatchBody) { llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end"); - llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); // Cleanups must call objc_end_catch. - // - // FIXME: It seems incorrect for objc_begin_catch to be inside this - // context, but this matches gcc. CGF.PushCleanupBlock(MatchEnd); - CGF.setInvokeDest(MatchHandler); llvm::Value *ExcObject = CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc); @@ -5636,25 +5668,37 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam)); } + // Exceptions inside the catch block must be rethrown. We set a special + // purpose invoke destination for this which just collects the thrown + // exception and overwrites the object in RethrowPtr, branches through the + // match.end to make sure we call objc_end_catch, before branching to the + // rethrow handler. + llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); + CGF.setInvokeDest(MatchHandler); CGF.ObjCEHValueStack.push_back(ExcObject); CGF.EmitStmt(CatchBody); CGF.ObjCEHValueStack.pop_back(); + CGF.setInvokeDest(0); CGF.EmitBranchThroughCleanup(FinallyEnd); - CGF.EmitBlock(MatchHandler); - - llvm::Value *Exc = CGF.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 Args; - Args.push_back(Exc); - Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); - CGF.Builder.CreateStore(Exc, RethrowPtr); - CGF.EmitBranchThroughCleanup(FinallyRethrow); + // Don't emit the extra match handler if there we no unprotected calls in + // the catch block. + if (MatchHandler->use_empty()) { + delete MatchHandler; + } else { + CGF.EmitBlock(MatchHandler); + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + CGF.Builder.CreateCall3(llvm_eh_selector, + Exc, ObjCTypes.getEHPersonalityPtr(), + llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0), + "unused_eh_selector"); + CGF.Builder.CreateStore(Exc, RethrowPtr); + CGF.EmitBranchThroughCleanup(FinallyRethrow); + } CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock(); @@ -5666,8 +5710,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.createBasicBlock("match.end.handler"); llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(), - Cont, MatchEndHandler, - Args.begin(), Args.begin()); + Cont, MatchEndHandler); CGF.EmitBlock(Cont); if (Info.SwitchBlock) @@ -5676,15 +5719,14 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(Info.EndBlock); CGF.EmitBlock(MatchEndHandler); - Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *Exc = CGF.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(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + CGF.Builder.CreateCall3(llvm_eh_selector, + Exc, ObjCTypes.getEHPersonalityPtr(), + llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0), + "unused_eh_selector"); CGF.Builder.CreateStore(Exc, RethrowPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); @@ -5723,9 +5765,19 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Branch around the rethrow code. CGF.EmitBranch(FinallyEnd); + // Generate the rethrow code, taking care to use an invoke if we are in a + // nested exception scope. CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), - CGF.Builder.CreateLoad(RethrowPtr)); + if (PrevLandingPad) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(ObjCTypes.getUnwindResumeOrRethrowFn(), + Cont, PrevLandingPad, + CGF.Builder.CreateLoad(RethrowPtr)); + CGF.EmitBlock(Cont); + } else { + CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), + CGF.Builder.CreateLoad(RethrowPtr)); + } CGF.Builder.CreateUnreachable(); CGF.EmitBlock(FinallyEnd); @@ -5816,7 +5868,8 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden) Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); - Entry->setAlignment(8); + Entry->setAlignment(CGM.getTargetData().getABITypeAlignment( + ObjCTypes.EHTypeTy)); if (ForDefinition) { Entry->setSection("__DATA,__objc_const"); diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index e478394..654ad0a 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -122,8 +122,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class = 0, const ObjCMethodDecl *Method = 0) = 0; /// Generate an Objective-C message send operation to the super @@ -167,6 +167,9 @@ public: /// Return the runtime function for setting properties. virtual llvm::Constant *GetPropertySetFunction() = 0; + // API for atomic copying of qualified aggregates in setter/getter. + virtual llvm::Constant *GetCopyStructFunction() = 0; + /// GetClass - Return a reference to the class for the given /// interface decl. virtual llvm::Value *GetClass(CGBuilderTy &Builder, diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 1caec97..aec1c45 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -31,8 +31,8 @@ class RTTIBuilder { /// descriptor of the given type. llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); - /// BuildVtablePointer - Build the vtable pointer for the given type. - void BuildVtablePointer(const Type *Ty); + /// BuildVTablePointer - Build the vtable pointer for the given type. + void BuildVTablePointer(const Type *Ty); /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b. @@ -148,6 +148,9 @@ public: }; /// BuildTypeInfo - Build the RTTI type info struct for the given type. + /// + /// \param Force - true to force the creation of this RTTI value + /// \param ForEH - true if this is for exception handling llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); }; } @@ -242,9 +245,10 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { } /// ShouldUseExternalRTTIDescriptor - Returns whether the type information for -/// the given type exists somewhere else, and that we should not emit the typ +/// the given type exists somewhere else, and that we should not emit the type /// information in this translation unit. -bool ShouldUseExternalRTTIDescriptor(QualType Ty) { +static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, + QualType Ty) { // Type info for builtin types is defined in the standard library. if (const BuiltinType *BuiltinTy = dyn_cast(Ty)) return TypeInfoIsInStandardLibrary(BuiltinTy); @@ -254,6 +258,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) { if (const PointerType *PointerTy = dyn_cast(Ty)) return TypeInfoIsInStandardLibrary(PointerTy); + // If RTTI is disabled, don't consider key functions. + if (!Context.getLangOptions().RTTI) return false; + if (const RecordType *RecordTy = dyn_cast(Ty)) { const CXXRecordDecl *RD = cast(RecordTy->getDecl()); if (!RD->hasDefinition()) @@ -337,7 +344,7 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) { if (const RecordType *Record = dyn_cast(Ty)) { const CXXRecordDecl *RD = cast(Record->getDecl()); if (RD->isDynamicClass()) - return CodeGenModule::getVtableLinkage(RD); + return CodeGenModule::getVTableLinkage(RD); } return llvm::GlobalValue::WeakODRLinkage; @@ -375,8 +382,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { return true; } -void RTTIBuilder::BuildVtablePointer(const Type *Ty) { - const char *VtableName; +void RTTIBuilder::BuildVTablePointer(const Type *Ty) { + const char *VTableName; switch (Ty->getTypeClass()) { default: assert(0 && "Unhandled type!"); @@ -386,24 +393,24 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { case Type::Vector: case Type::ExtVector: // abi::__fundamental_type_info. - VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; + VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; break; case Type::ConstantArray: case Type::IncompleteArray: // abi::__array_type_info. - VtableName = "_ZTVN10__cxxabiv117__array_type_infoE"; + VTableName = "_ZTVN10__cxxabiv117__array_type_infoE"; break; case Type::FunctionNoProto: case Type::FunctionProto: // abi::__function_type_info. - VtableName = "_ZTVN10__cxxabiv120__function_type_infoE"; + VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; break; case Type::Enum: // abi::__enum_type_info. - VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; + VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; break; case Type::Record: { @@ -412,13 +419,13 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { if (!RD->hasDefinition() || !RD->getNumBases()) { // abi::__class_type_info. - VtableName = "_ZTVN10__cxxabiv117__class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv117__class_type_infoE"; } else if (CanUseSingleInheritance(RD)) { // abi::__si_class_type_info. - VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; } else { // abi::__vmi_class_type_info. - VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; } break; @@ -426,30 +433,31 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { case Type::Pointer: // abi::__pointer_type_info. - VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; + VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; break; case Type::MemberPointer: // abi::__pointer_to_member_type_info. - VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; + VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; break; } - llvm::Constant *Vtable = - CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy); + llvm::Constant *VTable = + CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy); const llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); // The vtable address point is 2. llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); - Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1); - Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy); + VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1); + VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy); - Fields.push_back(Vtable); + Fields.push_back(VTable); } -llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, + bool Force) { // We want to operate on the canonical type. Ty = CGM.getContext().getCanonicalType(Ty); @@ -463,13 +471,13 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); // Check if there is already an external RTTI descriptor for this type. - if (!Force && ShouldUseExternalRTTIDescriptor(Ty)) + if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty)) return GetAddrOfExternalRTTIDescriptor(Ty); llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty); // Add the vtable pointer. - BuildVtablePointer(cast(Ty)); + BuildVTablePointer(cast(Ty)); // And the name. Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage)); @@ -782,42 +790,17 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0))); } -llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) { - if (!getContext().getLangOptions().RTTI) { +llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, + bool ForEH) { + // Return a bogus pointer if RTTI is disabled, unless it's for EH. + // FIXME: should we even be calling this method if RTTI is disabled + // and it's not for EH? + if (!ForEH && !getContext().getLangOptions().RTTI) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); return llvm::Constant::getNullValue(Int8PtrTy); } - - return RTTIBuilder(*this).BuildTypeInfo(Ty); -} -// Try to find the magic class __cxxabiv1::__fundamental_type_info. If -// exists and has a destructor, we will emit the typeinfo for the fundamental -// types. This is the same behaviour as GCC. -static CXXRecordDecl *FindMagicClass(ASTContext &AC) { - const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1"); - DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII); - TranslationUnitDecl *TUD = AC.getTranslationUnitDecl(); - DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN); - if (NamespaceLookup.first == NamespaceLookup.second) - return NULL; - const NamespaceDecl *Namespace = - dyn_cast(*NamespaceLookup.first); - if (!Namespace) - return NULL; - - const IdentifierInfo &ClassII = AC.Idents.get("__fundamental_type_info"); - DeclarationName ClassDN = AC.DeclarationNames.getIdentifier(&ClassII); - DeclContext::lookup_const_result ClassLookup = Namespace->lookup(ClassDN); - if (ClassLookup.first == ClassLookup.second) - return NULL; - CXXRecordDecl *Class = dyn_cast(*ClassLookup.first); - - if (Class->hasDefinition() && Class->isDynamicClass() && - Class->getDestructor(AC)) - return Class; - - return NULL; + return RTTIBuilder(*this).BuildTypeInfo(Ty); } void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { @@ -829,12 +812,6 @@ void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { } void CodeGenModule::EmitFundamentalRTTIDescriptors() { - CXXRecordDecl *RD = FindMagicClass(getContext()); - if (!RD) - return; - - getVTables().GenerateClassData(getVtableLinkage(RD), RD); - QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty, Context.Char16Ty, Context.UnsignedLongLongTy, Context.LongLongTy, Context.WCharTy, diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index fd1775e..9f966fb 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -13,22 +13,137 @@ #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" namespace llvm { + class raw_ostream; class Type; } namespace clang { namespace CodeGen { +/// \brief Helper object for describing how to generate the code for access to a +/// bit-field. +/// +/// This structure is intended to describe the "policy" of how the bit-field +/// should be accessed, which may be target, language, or ABI dependent. class CGBitFieldInfo { public: - CGBitFieldInfo(unsigned FieldNo, unsigned Start, unsigned Size, - bool IsSigned) - : FieldNo(FieldNo), Start(Start), Size(Size), IsSigned(IsSigned) {} + /// Descriptor for a single component of a bit-field access. The entire + /// bit-field is constituted of a bitwise OR of all of the individual + /// components. + /// + /// Each component describes an accessed value, which is how the component + /// should be transferred to/from memory, and a target placement, which is how + /// that component fits into the constituted bit-field. The pseudo-IR for a + /// load is: + /// + /// %0 = gep %base, 0, FieldIndex + /// %1 = gep (i8*) %0, FieldByteOffset + /// %2 = (i(AccessWidth) *) %1 + /// %3 = load %2, align AccessAlignment + /// %4 = shr %3, FieldBitStart + /// + /// and the composed bit-field is formed as the boolean OR of all accesses, + /// masked to TargetBitWidth bits and shifted to TargetBitOffset. + struct AccessInfo { + /// Offset of the field to load in the LLVM structure, if any. + unsigned FieldIndex; + + /// Byte offset from the field address, if any. This should generally be + /// unused as the cleanest IR comes from having a well-constructed LLVM type + /// with proper GEP instructions, but sometimes its use is required, for + /// example if an access is intended to straddle an LLVM field boundary. + unsigned FieldByteOffset; + + /// Bit offset in the accessed value to use. The width is implied by \see + /// TargetBitWidth. + unsigned FieldBitStart; + + /// Bit width of the memory access to perform. + unsigned AccessWidth; + + /// The alignment of the memory access, or 0 if the default alignment should + /// be used. + // + // FIXME: Remove use of 0 to encode default, instead have IRgen do the right + // thing when it generates the code, if avoiding align directives is + // desired. + unsigned AccessAlignment; + + /// Offset for the target value. + unsigned TargetBitOffset; + + /// Number of bits in the access that are destined for the bit-field. + unsigned TargetBitWidth; + }; - unsigned FieldNo; - unsigned Start; +private: + /// The components to use to access the bit-field. We may need up to three + /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte + /// accesses). + // + // FIXME: De-hardcode this, just allocate following the struct. + AccessInfo Components[3]; + + /// The total size of the bit-field, in bits. unsigned Size; + + /// The number of access components to use. + unsigned NumComponents; + + /// Whether the bit-field is signed. bool IsSigned : 1; + +public: + CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components, + bool IsSigned) : Size(Size), NumComponents(NumComponents), + IsSigned(IsSigned) { + assert(NumComponents <= 3 && "invalid number of components!"); + for (unsigned i = 0; i != NumComponents; ++i) + Components[i] = _Components[i]; + + // Check some invariants. + unsigned AccessedSize = 0; + for (unsigned i = 0, e = getNumComponents(); i != e; ++i) { + const AccessInfo &AI = getComponent(i); + AccessedSize += AI.TargetBitWidth; + + // We shouldn't try to load 0 bits. + assert(AI.TargetBitWidth > 0); + + // We can't load more bits than we accessed. + assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth); + + // We shouldn't put any bits outside the result size. + assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size); + } + + // Check that the total number of target bits matches the total bit-field + // size. + assert(AccessedSize == Size && "Total size does not match accessed size!"); + } + +public: + /// \brief Check whether this bit-field access is (i.e., should be sign + /// extended on loads). + bool isSigned() const { return IsSigned; } + + /// \brief Get the size of the bit-field, in bits. + unsigned getSize() const { return Size; } + + /// @name Component Access + /// @{ + + unsigned getNumComponents() const { return NumComponents; } + + const AccessInfo &getComponent(unsigned Index) const { + assert(Index < getNumComponents() && "Invalid access!"); + return Components[Index]; + } + + /// @} + + void print(llvm::raw_ostream &OS) const; + void dump() const; }; /// CGRecordLayout - This class handles struct and union layout info while @@ -71,15 +186,15 @@ public: return ContainsPointerToDataMember; } - /// \brief Return the BitFieldInfo that corresponds to the field FD. + /// \brief Return llvm::StructType element number that corresponds to the + /// field FD. unsigned getLLVMFieldNo(const FieldDecl *FD) const { assert(!FD->isBitField() && "Invalid call for bit-field decl!"); assert(FieldInfo.count(FD) && "Invalid field for record!"); return FieldInfo.lookup(FD); } - /// \brief Return llvm::StructType element number that corresponds to the - /// field FD. + /// \brief Return the BitFieldInfo that corresponds to the field FD. const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const { assert(FD->isBitField() && "Invalid call for non bit-field decl!"); llvm::DenseMap::const_iterator @@ -87,6 +202,9 @@ public: assert(it != BitFields.end() && "Unable to find bitfield info"); return it->second; } + + void print(llvm::raw_ostream &OS) const; + void dump() const; }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 4b9ec66..6302cf8 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -18,8 +18,10 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "CodeGenTypes.h" -#include "llvm/Type.h" #include "llvm/DerivedTypes.h" +#include "llvm/Type.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -67,6 +69,11 @@ private: /// NextFieldOffsetInBytes - Holds the next field offset in bytes. uint64_t NextFieldOffsetInBytes; + /// LayoutUnionField - Will layout a field in an union and return the type + /// that the field will have. + const llvm::Type *LayoutUnionField(const FieldDecl *Field, + const ASTRecordLayout &Layout); + /// LayoutUnion - Will layout a union RecordDecl. void LayoutUnion(const RecordDecl *D); @@ -87,10 +94,6 @@ private: /// AppendField - Appends a field with the given offset and type. void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - /// AppendPadding - Appends enough padding bytes so that the total struct - /// size matches the alignment of the passed in type. - void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - /// AppendPadding - Appends enough padding bytes so that the total /// struct size is a multiple of the field alignment. void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); @@ -103,7 +106,6 @@ private: void AppendTailPadding(uint64_t RecordSize); unsigned getTypeAlignment(const llvm::Type *Ty) const; - uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; /// CheckForPointerToDataMember - Check if the given type contains a pointer /// to data member. @@ -145,6 +147,104 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { LayoutFields(D); } +static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types, + const FieldDecl *FD, + uint64_t FieldOffset, + uint64_t FieldSize) { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD); + uint64_t ContainingTypeSizeInBits = RL.getSize(); + unsigned ContainingTypeAlign = RL.getAlignment(); + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType()); + uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty); + uint64_t TypeSizeInBits = TypeSizeInBytes * 8; + + bool IsSigned = FD->getType()->isSignedIntegerType(); + + if (FieldSize > TypeSizeInBits) { + // We have a wide bit-field. The extra bits are only used for padding, so + // if we have a bitfield of type T, with size N: + // + // T t : N; + // + // We can just assume that it's: + // + // T t : sizeof(T); + // + FieldSize = TypeSizeInBits; + } + + // Compute the access components. The policy we use is to start by attempting + // to access using the width of the bit-field type itself and to always access + // at aligned indices of that type. If such an access would fail because it + // extends past the bound of the type, then we reduce size to the next smaller + // power of two and retry. The current algorithm assumes pow2 sized types, + // although this is easy to fix. + // + // FIXME: This algorithm is wrong on big-endian systems, I think. + assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!"); + CGBitFieldInfo::AccessInfo Components[3]; + unsigned NumComponents = 0; + unsigned AccessedTargetBits = 0; // The tumber of target bits accessed. + unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt. + + // Round down from the field offset to find the first access position that is + // at an aligned offset of the initial access type. + uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth); + + // Adjust initial access size to fit within record. + while (AccessWidth > 8 && + AccessStart + AccessWidth > ContainingTypeSizeInBits) { + AccessWidth >>= 1; + AccessStart = FieldOffset - (FieldOffset % AccessWidth); + } + + while (AccessedTargetBits < FieldSize) { + // Check that we can access using a type of this size, without reading off + // the end of the structure. This can occur with packed structures and + // -fno-bitfield-type-align, for example. + if (AccessStart + AccessWidth > ContainingTypeSizeInBits) { + // If so, reduce access size to the next smaller power-of-two and retry. + AccessWidth >>= 1; + assert(AccessWidth >= 8 && "Cannot access under byte size!"); + continue; + } + + // Otherwise, add an access component. + + // First, compute the bits inside this access which are part of the + // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the + // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits + // in the target that we are reading. + assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!"); + assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!"); + uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset); + uint64_t AccessBitsInFieldSize = + std::min(AccessWidth + AccessStart, + FieldOffset + FieldSize) - AccessBitsInFieldStart; + + assert(NumComponents < 3 && "Unexpected number of components!"); + CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++]; + AI.FieldIndex = 0; + // FIXME: We still follow the old access pattern of only using the field + // byte offset. We should switch this once we fix the struct layout to be + // pretty. + AI.FieldByteOffset = AccessStart / 8; + AI.FieldBitStart = AccessBitsInFieldStart - AccessStart; + AI.AccessWidth = AccessWidth; + AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8; + AI.TargetBitOffset = AccessedTargetBits; + AI.TargetBitWidth = AccessBitsInFieldSize; + + AccessStart += AccessWidth; + AccessedTargetBits += AI.TargetBitWidth; + } + + assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!"); + return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned); +} + void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, uint64_t FieldOffset) { uint64_t FieldSize = @@ -175,14 +275,9 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, assert(NumBytesToAppend && "No bytes to append!"); } - const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); - uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8; - - bool IsSigned = D->getType()->isSignedIntegerType(); - LLVMBitFields.push_back(LLVMBitFieldInfo( - D, CGBitFieldInfo(FieldOffset / TypeSizeInBits, - FieldOffset % TypeSizeInBits, - FieldSize, IsSigned))); + // Add the bit field info. + LLVMBitFields.push_back( + LLVMBitFieldInfo(D, ComputeBitFieldInfo(Types, D, FieldOffset, FieldSize))); AppendBytes(NumBytesToAppend); @@ -254,6 +349,35 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, return true; } +const llvm::Type * +CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, + const ASTRecordLayout &Layout) { + if (Field->isBitField()) { + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + + // Ignore zero sized bit fields. + if (FieldSize == 0) + return 0; + + const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext()); + unsigned NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize, 8) / 8; + + if (NumBytesToAppend > 1) + FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend); + + // Add the bit field info. + LLVMBitFields.push_back( + LLVMBitFieldInfo(Field, ComputeBitFieldInfo(Types, Field, 0, FieldSize))); + return FieldTy; + } + + // This is a regular union field. + LLVMFields.push_back(LLVMFieldInfo(Field, 0)); + return Types.ConvertTypeForMemRecursive(Field->getType()); +} + void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!"); @@ -270,28 +394,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { assert(Layout.getFieldOffset(FieldNo) == 0 && "Union field offset did not start at the beginning of record!"); + const llvm::Type *FieldTy = LayoutUnionField(*Field, Layout); - if (Field->isBitField()) { - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); - - // Ignore zero sized bit fields. - if (FieldSize == 0) - continue; - - // Add the bit field info. - bool IsSigned = Field->getType()->isSignedIntegerType(); - LLVMBitFields.push_back(LLVMBitFieldInfo( - *Field, CGBitFieldInfo(0, 0, FieldSize, - IsSigned))); - } else { - LLVMFields.push_back(LLVMFieldInfo(*Field, 0)); - } + if (!FieldTy) + continue; HasOnlyZeroSizedBitFields = false; - const llvm::Type *FieldTy = - Types.ConvertTypeForMemRecursive(Field->getType()); unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy); @@ -334,7 +443,7 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD, llvm::Type::getInt8PtrTy(Types.getLLVMContext()); assert(NextFieldOffsetInBytes == 0 && - "Vtable pointer must come first!"); + "VTable pointer must come first!"); AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); } } @@ -388,7 +497,7 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(FieldTy)); - uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy); + uint64_t FieldSizeInBytes = Types.getTargetData().getTypeAllocSize(FieldTy); FieldTypes.push_back(FieldTy); @@ -396,12 +505,6 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, BitsAvailableInLastField = 0; } -void -CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, - const llvm::Type *FieldTy) { - AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy)); -} - void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment) { assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && @@ -439,10 +542,6 @@ unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { return Types.getTargetData().getABITypeAlignment(Ty); } -uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const { - return Types.getTargetData().getTypeAllocSize(Ty); -} - void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { // This record already contains a member pointer. if (ContainsPointerToDataMember) @@ -481,9 +580,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(), Builder.FieldTypes, Builder.Packed); - assert(getContext().getASTRecordLayout(D).getSize() / 8 == - getTargetData().getTypeAllocSize(Ty) && - "Type size mismatch!"); CGRecordLayout *RL = new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); @@ -496,5 +592,121 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) RL->BitFields.insert(Builder.LLVMBitFields[i]); + // Dump the layout, if requested. + if (getContext().getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping IRgen Record Layout\n"; + llvm::errs() << "Record: "; + D->dump(); + llvm::errs() << "\nLayout: "; + RL->dump(); + } + +#ifndef NDEBUG + // Verify that the computed LLVM struct size matches the AST layout size. + uint64_t TypeSizeInBits = getContext().getASTRecordLayout(D).getSize(); + assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) && + "Type size mismatch!"); + + // Verify that the LLVM and AST field offsets agree. + const llvm::StructType *ST = + dyn_cast(RL->getLLVMType()); + const llvm::StructLayout *SL = getTargetData().getStructLayout(ST); + + const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); + RecordDecl::field_iterator it = D->field_begin(); + for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { + const FieldDecl *FD = *it; + + // For non-bit-fields, just check that the LLVM struct offset matches the + // AST offset. + if (!FD->isBitField()) { + unsigned FieldNo = RL->getLLVMFieldNo(FD); + assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && + "Invalid field offset!"); + continue; + } + + // Ignore unnamed bit-fields. + if (!FD->getDeclName()) + continue; + + const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); + + // Verify that every component access is within the structure. + uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex); + uint64_t AccessBitOffset = FieldOffset + AI.FieldByteOffset * 8; + assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits && + "Invalid bit-field access (out of range)!"); + } + } +#endif + return RL; } + +void CGRecordLayout::print(llvm::raw_ostream &OS) const { + OS << " > BFIs; + for (llvm::DenseMap::const_iterator + it = BitFields.begin(), ie = BitFields.end(); + it != ie; ++it) { + const RecordDecl *RD = it->first->getParent(); + unsigned Index = 0; + for (RecordDecl::field_iterator + it2 = RD->field_begin(); *it2 != it->first; ++it2) + ++Index; + BFIs.push_back(std::make_pair(Index, &it->second)); + } + llvm::array_pod_sort(BFIs.begin(), BFIs.end()); + for (unsigned i = 0, e = BFIs.size(); i != e; ++i) { + OS.indent(4); + BFIs[i].second->print(OS); + OS << "\n"; + } + + OS << "]>\n"; +} + +void CGRecordLayout::dump() const { + print(llvm::errs()); +} + +void CGBitFieldInfo::print(llvm::raw_ostream &OS) const { + OS << "\n"; + } + OS.indent(4); + } + OS << "]>"; +} + +void CGBitFieldInfo::dump() const { + print(llvm::errs()); +} diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index ae2f791..a914c80d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -160,7 +160,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EmitStmt(*I); if (DI) { - DI->setLocation(S.getLBracLoc()); + DI->setLocation(S.getRBracLoc()); DI->EmitRegionEnd(CurFn, Builder); } @@ -205,6 +205,8 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) { } void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + // Fall out of the current block (if necessary). EmitBranch(BB); @@ -225,7 +227,12 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { } } - CurFn->getBasicBlockList().push_back(BB); + // Place the block after the current block, if possible, or else at + // the end of the function. + if (CurBB && CurBB->getParent()) + CurFn->getBasicBlockList().insertAfter(CurBB, BB); + else + CurFn->getBasicBlockList().push_back(BB); Builder.SetInsertPoint(BB); } @@ -974,19 +981,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { unsigned InputNo; for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) { TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo]; - if (Input.hasTiedOperand() && - Input.getTiedOperand() == i) + if (Input.hasTiedOperand() && Input.getTiedOperand() == i) break; } assert(InputNo != S.getNumInputs() && "Didn't find matching input!"); QualType InputTy = S.getInputExpr(InputNo)->getType(); - QualType OutputTy = OutExpr->getType(); + QualType OutputType = OutExpr->getType(); uint64_t InputSize = getContext().getTypeSize(InputTy); - if (getContext().getTypeSize(OutputTy) < InputSize) { - // Form the asm to return the value as a larger integer type. - ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize); + if (getContext().getTypeSize(OutputType) < InputSize) { + // Form the asm to return the value as a larger integer or fp type. + ResultRegTypes.back() = ConvertType(InputTy); } } } else { @@ -1036,17 +1042,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // that is usually cheaper, but LLVM IR should really get an anyext someday. if (Info.hasTiedOperand()) { unsigned Output = Info.getTiedOperand(); - QualType OutputTy = S.getOutputExpr(Output)->getType(); + QualType OutputType = S.getOutputExpr(Output)->getType(); QualType InputTy = InputExpr->getType(); - if (getContext().getTypeSize(OutputTy) > + if (getContext().getTypeSize(OutputType) > getContext().getTypeSize(InputTy)) { // Use ptrtoint as appropriate so that we can do our extension. if (isa(Arg->getType())) Arg = Builder.CreatePtrToInt(Arg, - llvm::IntegerType::get(VMContext, LLVMPointerWidth)); - unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy); - Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, OutputSize)); + llvm::IntegerType::get(VMContext, LLVMPointerWidth)); + const llvm::Type *OutputTy = ConvertType(OutputType); + if (isa(OutputTy)) + Arg = Builder.CreateZExt(Arg, OutputTy); + else + Arg = Builder.CreateFPExt(Arg, OutputTy); } } @@ -1102,6 +1111,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end()); Result->addAttribute(~0, llvm::Attribute::NoUnwind); + // Slap the source location of the inline asm into a !srcloc metadata on the + // call. + unsigned LocID = S.getAsmString()->getLocStart().getRawEncoding(); + llvm::Value *LocIDC = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LocID); + Result->setMetadata("srcloc", llvm::MDNode::get(VMContext, &LocIDC, 1)); // Extract all of the register value results from the asm. std::vector RegResults; @@ -1121,14 +1136,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // the expression, do the conversion. if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { const llvm::Type *TruncTy = ResultTruncRegTypes[i]; - // Truncate the integer result to the right size, note that - // ResultTruncRegTypes can be a pointer. - uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); - Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize)); - - if (Tmp->getType() != TruncTy) { - assert(isa(TruncTy)); + + // Truncate the integer result to the right size, note that TruncTy can be + // a pointer. + if (TruncTy->isFloatingPointTy()) + Tmp = Builder.CreateFPTrunc(Tmp, TruncTy); + else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) { + uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); + Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, + (unsigned)ResSize)); Tmp = Builder.CreateIntToPtr(Tmp, TruncTy); + } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) { + uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType()); + Tmp = Builder.CreatePtrToInt(Tmp, llvm::IntegerType::get(VMContext, + (unsigned)TmpSize)); + Tmp = Builder.CreateTrunc(Tmp, TruncTy); + } else if (TruncTy->isIntegerTy()) { + Tmp = Builder.CreateTrunc(Tmp, TruncTy); } } diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index 6d38ab9..a8f0467 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, "Pushed the same temporary twice; AST is likely wrong"); llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); - llvm::Value *CondPtr = 0; + llvm::AllocaInst *CondPtr = 0; // Check if temporaries need to be conditional. If so, we'll create a // condition boolean, initialize it to 0 and @@ -32,10 +32,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, // Initialize it to false. This initialization takes place right after // the alloca insert point. - llvm::StoreInst *SI = - new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr); - llvm::BasicBlock *Block = AllocaInsertPt->getParent(); - Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI); + InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext)); // Now set it to true. Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); @@ -64,7 +61,8 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, } EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); + Dtor_Complete, /*ForVirtualBase=*/false, + Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. @@ -107,7 +105,7 @@ void CodeGenFunction::PopCXXTemporary() { } EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); + Dtor_Complete, /*ForVirtualBase=*/false, Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 91d9f76..15e5648 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -43,7 +43,7 @@ class VTTBuilder { /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived /// class. - llvm::DenseMap SubVTTIndicies; + llvm::DenseMap SubVTTIndicies; /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of /// all subobjects of the most derived class. @@ -116,8 +116,7 @@ public: } /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. - const llvm::DenseMap & - getSubVTTIndicies() const { + const llvm::DenseMap &getSubVTTIndicies() const { return SubVTTIndicies; } @@ -179,13 +178,14 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, // The vtable is a construction vtable, look in the construction vtable // address points. AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); } else { // Just get the address point for the regular vtable. AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + assert(AddressPoint != 0 && "Did not find vtable address point!"); } if (!AddressPoint) AddressPoint = 0; - assert(AddressPoint != 0 && "Did not find an address point!"); llvm::Value *Idxs[] = { llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0), @@ -340,7 +340,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { if (!IsPrimaryVTT) { // Remember the sub-VTT index. - SubVTTIndicies[RD] = VTTComponents.size(); + SubVTTIndicies[Base] = VTTComponents.size(); } AddressPointsMapTy AddressPoints; @@ -434,25 +434,25 @@ bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) { } uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *Base) { - ClassPairTy ClassPair(RD, Base); + BaseSubobject Base) { + BaseSubobjectPairTy ClassSubobjectPair(RD, Base); - SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair); + SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair); if (I != SubVTTIndicies.end()) return I->second; VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); - for (llvm::DenseMap::const_iterator I = + for (llvm::DenseMap::const_iterator I = Builder.getSubVTTIndicies().begin(), E = Builder.getSubVTTIndicies().end(); I != E; ++I) { // Insert all indices. - ClassPairTy ClassPair(RD, I->first); + BaseSubobjectPairTy ClassSubobjectPair(RD, I->first); - SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); + SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second)); } - I = SubVTTIndicies.find(ClassPair); + I = SubVTTIndicies.find(ClassSubobjectPair); assert(I != SubVTTIndicies.end() && "Did not find index!"); return I->second; diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp new file mode 100644 index 0000000..159753a --- /dev/null +++ b/lib/CodeGen/CGVTables.cpp @@ -0,0 +1,3167 @@ +//===--- CGVTables.cpp - Emit LLVM Code for C++ vtables -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of virtual tables. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "CodeGenFunction.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include +#include + +using namespace clang; +using namespace CodeGen; + +namespace { + +/// BaseOffset - Represents an offset from a derived class to a direct or +/// indirect base class. +struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + + /// VirtualBase - If the path from the derived class to the base class + /// involves a virtual base class, this holds its declaration. + const CXXRecordDecl *VirtualBase; + + /// NonVirtualOffset - The offset from the derived class to the base class. + /// (Or the offset from the virtual base class to the base class, if the + /// path from the derived class to the base class involves a virtual base + /// class. + int64_t NonVirtualOffset; + + BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } + + bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } +}; + +/// FinalOverriders - Contains the final overrider member functions for all +/// member functions in the base subobjects of a class. +class FinalOverriders { +public: + /// OverriderInfo - Information about a final overrider. + struct OverriderInfo { + /// Method - The method decl of the overrider. + const CXXMethodDecl *Method; + + /// Offset - the base offset of the overrider in the layout class. + uint64_t Offset; + + OverriderInfo() : Method(0), Offset(0) { } + }; + +private: + /// MostDerivedClass - The most derived class for which the final overriders + /// are stored. + const CXXRecordDecl *MostDerivedClass; + + /// MostDerivedClassOffset - If we're building final overriders for a + /// construction vtable, this holds the offset from the layout class to the + /// most derived class. + const uint64_t MostDerivedClassOffset; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if the final overriders are for a + /// construction vtable. + const CXXRecordDecl *LayoutClass; + + ASTContext &Context; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + /// BaseSubobjectMethodPairTy - Uniquely identifies a member function + /// in a base subobject. + typedef std::pair + BaseSubobjectMethodPairTy; + + typedef llvm::DenseMap OverridersMapTy; + + /// OverridersMap - The final overriders for all virtual member functions of + /// all the base subobjects of the most derived class. + OverridersMapTy OverridersMap; + + /// VisitedVirtualBases - A set of all the visited virtual bases, used to + /// avoid visiting virtual bases more than once. + llvm::SmallPtrSet VisitedVirtualBases; + + typedef llvm::DenseMap + AdjustmentOffsetsMapTy; + + /// ReturnAdjustments - Holds return adjustments for all the overriders that + /// need to perform return value adjustments. + AdjustmentOffsetsMapTy ReturnAdjustments; + + // FIXME: We might be able to get away with making this a SmallSet. + typedef llvm::SmallSetVector OffsetSetVectorTy; + + /// SubobjectOffsetsMapTy - This map is used for keeping track of all the + /// base subobject offsets that a single class declaration might refer to. + /// + /// For example, in: + /// + /// struct A { virtual void f(); }; + /// struct B1 : A { }; + /// struct B2 : A { }; + /// struct C : B1, B2 { virtual void f(); }; + /// + /// when we determine that C::f() overrides A::f(), we need to update the + /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map + /// will have the subobject offsets for both A copies. + typedef llvm::DenseMap + SubobjectOffsetsMapTy; + + /// ComputeFinalOverriders - Compute the final overriders for a given base + /// subobject (and all its direct and indirect bases). + void ComputeFinalOverriders(BaseSubobject Base, + bool BaseSubobjectIsVisitedVBase, + uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets); + + /// AddOverriders - Add the final overriders for this base subobject to the + /// map of final overriders. + void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets); + + /// PropagateOverrider - Propagate the NewMD overrider to all the functions + /// that OldMD overrides. For example, if we have: + /// + /// struct A { virtual void f(); }; + /// struct B : A { virtual void f(); }; + /// struct C : B { virtual void f(); }; + /// + /// and we want to override B::f with C::f, we also need to override A::f with + /// C::f. + void PropagateOverrider(const CXXMethodDecl *OldMD, + BaseSubobject NewBase, + uint64_t OverriderOffsetInLayoutClass, + const CXXMethodDecl *NewMD, + SubobjectOffsetsMapTy &Offsets); + + static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, + SubobjectOffsetsMapTy &Offsets); + +public: + FinalOverriders(const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, + const CXXRecordDecl *LayoutClass); + + /// getOverrider - Get the final overrider for the given method declaration in + /// the given base subobject. + OverriderInfo getOverrider(BaseSubobject Base, + const CXXMethodDecl *MD) const { + assert(OverridersMap.count(std::make_pair(Base, MD)) && + "Did not find overrider!"); + + return OverridersMap.lookup(std::make_pair(Base, MD)); + } + + /// getReturnAdjustmentOffset - Get the return adjustment offset for the + /// method decl in the given base subobject. Returns an empty base offset if + /// no adjustment is needed. + BaseOffset getReturnAdjustmentOffset(BaseSubobject Base, + const CXXMethodDecl *MD) const { + return ReturnAdjustments.lookup(std::make_pair(Base, MD)); + } + + /// dump - dump the final overriders. + void dump() { + assert(VisitedVirtualBases.empty() && + "Visited virtual bases aren't empty!"); + dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0)); + VisitedVirtualBases.clear(); + } + + /// dump - dump the final overriders for a base subobject, and all its direct + /// and indirect base subobjects. + void dump(llvm::raw_ostream &Out, BaseSubobject Base); +}; + +#define DUMP_OVERRIDERS 0 + +FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, + const CXXRecordDecl *LayoutClass) + : MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), + MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { + + // Compute the final overriders. + SubobjectOffsetsMapTy Offsets; + ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), + /*BaseSubobjectIsVisitedVBase=*/false, + MostDerivedClassOffset, Offsets); + VisitedVirtualBases.clear(); + +#if DUMP_OVERRIDERS + // And dump them (for now). + dump(); + + // Also dump the base offsets (for now). + for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(), + E = Offsets.end(); I != E; ++I) { + const OffsetSetVectorTy& OffsetSetVector = I->second; + + llvm::errs() << "Base offsets for "; + llvm::errs() << I->first->getQualifiedNameAsString() << '\n'; + + for (unsigned I = 0, E = OffsetSetVector.size(); I != E; ++I) + llvm::errs() << " " << I << " - " << OffsetSetVector[I] / 8 << '\n'; + } +#endif +} + +void FinalOverriders::AddOverriders(BaseSubobject Base, + uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets) { + const CXXRecordDecl *RD = Base.getBase(); + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // First, propagate the overrider. + PropagateOverrider(MD, Base, OffsetInLayoutClass, MD, Offsets); + + // Add the overrider as the final overrider of itself. + OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; + assert(!Overrider.Method && "Overrider should not exist yet!"); + + Overrider.Offset = OffsetInLayoutClass; + Overrider.Method = MD; + } +} + +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *DerivedRD, + const CXXBasePath &Path) { + int64_t NonVirtualOffset = 0; + + unsigned NonVirtualStart = 0; + const CXXRecordDecl *VirtualBase = 0; + + // First, look for the virtual base class. + for (unsigned I = 0, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + if (Element.Base->isVirtual()) { + // FIXME: Can we break when we find the first virtual base? + // (If we can't, can't we just iterate over the path in reverse order?) + NonVirtualStart = I + 1; + QualType VBaseType = Element.Base->getType(); + VirtualBase = + cast(VBaseType->getAs()->getDecl()); + } + } + + // Now compute the non-virtual offset. + for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + // Check the base class offset. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + + const RecordType *BaseType = Element.Base->getType()->getAs(); + const CXXRecordDecl *Base = cast(BaseType->getDecl()); + + NonVirtualOffset += Layout.getBaseClassOffset(Base); + } + + // FIXME: This should probably use CharUnits or something. Maybe we should + // even change the base offsets in ASTRecordLayout to be specified in + // CharUnits. + return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); + +} + +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *BaseRD, + const CXXRecordDecl *DerivedRD) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + + if (!const_cast(DerivedRD)-> + isDerivedFrom(const_cast(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return BaseOffset(); + } + + return ComputeBaseOffset(Context, DerivedRD, Paths.front()); +} + +static BaseOffset +ComputeReturnAdjustmentBaseOffset(ASTContext &Context, + const CXXMethodDecl *DerivedMD, + const CXXMethodDecl *BaseMD) { + const FunctionType *BaseFT = BaseMD->getType()->getAs(); + const FunctionType *DerivedFT = DerivedMD->getType()->getAs(); + + // Canonicalize the return types. + CanQualType CanDerivedReturnType = + Context.getCanonicalType(DerivedFT->getResultType()); + CanQualType CanBaseReturnType = + Context.getCanonicalType(BaseFT->getResultType()); + + assert(CanDerivedReturnType->getTypeClass() == + CanBaseReturnType->getTypeClass() && + "Types must have same type class!"); + + if (CanDerivedReturnType == CanBaseReturnType) { + // No adjustment needed. + return BaseOffset(); + } + + if (isa(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs()->getPointeeType(); + } else if (isa(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs()->getPointeeType(); + } else { + assert(false && "Unexpected return type!"); + } + + // We need to compare unqualified types here; consider + // const T *Base::foo(); + // T *Derived::foo(); + if (CanDerivedReturnType.getUnqualifiedType() == + CanBaseReturnType.getUnqualifiedType()) { + // No adjustment needed. + return BaseOffset(); + } + + const CXXRecordDecl *DerivedRD = + cast(cast(CanDerivedReturnType)->getDecl()); + + const CXXRecordDecl *BaseRD = + cast(cast(CanBaseReturnType)->getDecl()); + + return ComputeBaseOffset(Context, BaseRD, DerivedRD); +} + +void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, + BaseSubobject NewBase, + uint64_t OverriderOffsetInLayoutClass, + const CXXMethodDecl *NewMD, + SubobjectOffsetsMapTy &Offsets) { + for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(), + E = OldMD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + + // We want to override OverriddenMD in all subobjects, for example: + // + /// struct A { virtual void f(); }; + /// struct B1 : A { }; + /// struct B2 : A { }; + /// struct C : B1, B2 { virtual void f(); }; + /// + /// When overriding A::f with C::f we need to do so in both A subobjects. + const OffsetSetVectorTy &OffsetVector = Offsets[OverriddenRD]; + + // Go through all the subobjects. + for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { + uint64_t Offset = OffsetVector[I]; + + BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset); + BaseSubobjectMethodPairTy SubobjectAndMethod = + std::make_pair(OverriddenSubobject, OverriddenMD); + + OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod]; + + assert(Overrider.Method && "Did not find existing overrider!"); + + // Check if we need return adjustments or base adjustments. + // (We don't want to do this for pure virtual member functions). + if (!NewMD->isPure()) { + // Get the return adjustment base offset. + BaseOffset ReturnBaseOffset = + ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD); + + if (!ReturnBaseOffset.isEmpty()) { + // Store the return adjustment base offset. + ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; + } + } + + // Set the new overrider. + Overrider.Offset = OverriderOffsetInLayoutClass; + Overrider.Method = NewMD; + + // And propagate it further. + PropagateOverrider(OverriddenMD, NewBase, OverriderOffsetInLayoutClass, + NewMD, Offsets); + } + } +} + +void +FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, + SubobjectOffsetsMapTy &Offsets) { + // Iterate over the new offsets. + for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(), + E = NewOffsets.end(); I != E; ++I) { + const CXXRecordDecl *NewRD = I->first; + const OffsetSetVectorTy& NewOffsetVector = I->second; + + OffsetSetVectorTy &OffsetVector = Offsets[NewRD]; + + // Merge the new offsets set vector into the old. + OffsetVector.insert(NewOffsetVector.begin(), NewOffsetVector.end()); + } +} + +void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, + bool BaseSubobjectIsVisitedVBase, + uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + SubobjectOffsetsMapTy NewOffsets; + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase; + uint64_t BaseOffset; + uint64_t BaseOffsetInLayoutClass; + if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) + IsVisitedVirtualBase = true; + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); + BaseOffsetInLayoutClass = Layout.getBaseClassOffset(BaseDecl) + + OffsetInLayoutClass; + } + + // Compute the final overriders for this base. + // We always want to compute the final overriders, even if the base is a + // visited virtual base. Consider: + // + // struct A { + // virtual void f(); + // virtual void g(); + // }; + // + // struct B : virtual A { + // void f(); + // }; + // + // struct C : virtual A { + // void g (); + // }; + // + // struct D : B, C { }; + // + // Here, we still want to compute the overriders for A as a base of C, + // because otherwise we'll miss that C::g overrides A::f. + ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), + IsVisitedVirtualBase, BaseOffsetInLayoutClass, + NewOffsets); + } + + /// Now add the overriders for this particular subobject. + /// (We don't want to do this more than once for a virtual base). + if (!BaseSubobjectIsVisitedVBase) + AddOverriders(Base, OffsetInLayoutClass, NewOffsets); + + // And merge the newly discovered subobject offsets. + MergeSubobjectOffsets(NewOffsets, Offsets); + + /// Finally, add the offset for our own subobject. + Offsets[RD].insert(Base.getBaseOffset()); +} + +void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + uint64_t BaseOffset; + if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) { + // We've visited this base before. + continue; + } + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + + Base.getBaseOffset(); + } + + dump(Out, BaseSubobject(BaseDecl, BaseOffset)); + } + + Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; + Out << Base.getBaseOffset() / 8 << ")\n"; + + // Now dump the overriders for this base subobject. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + OverriderInfo Overrider = getOverrider(Base, MD); + + Out << " " << MD->getQualifiedNameAsString() << " - ("; + Out << Overrider.Method->getQualifiedNameAsString(); + Out << ", " << ", " << Overrider.Offset / 8 << ')'; + + AdjustmentOffsetsMapTy::const_iterator AI = + ReturnAdjustments.find(std::make_pair(Base, MD)); + if (AI != ReturnAdjustments.end()) { + const BaseOffset &Offset = AI->second; + + Out << " [ret-adj: "; + if (Offset.VirtualBase) + Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; + + Out << Offset.NonVirtualOffset << " nv]"; + } + + Out << "\n"; + } +} + +/// VTableComponent - Represents a single component in a vtable. +class VTableComponent { +public: + enum Kind { + CK_VCallOffset, + CK_VBaseOffset, + CK_OffsetToTop, + CK_RTTI, + CK_FunctionPointer, + + /// CK_CompleteDtorPointer - A pointer to the complete destructor. + CK_CompleteDtorPointer, + + /// CK_DeletingDtorPointer - A pointer to the deleting destructor. + CK_DeletingDtorPointer, + + /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer + /// will end up never being called. Such vtable function pointers are + /// represented as a CK_UnusedFunctionPointer. + CK_UnusedFunctionPointer + }; + + static VTableComponent MakeVCallOffset(int64_t Offset) { + return VTableComponent(CK_VCallOffset, Offset); + } + + static VTableComponent MakeVBaseOffset(int64_t Offset) { + return VTableComponent(CK_VBaseOffset, Offset); + } + + static VTableComponent MakeOffsetToTop(int64_t Offset) { + return VTableComponent(CK_OffsetToTop, Offset); + } + + static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { + return VTableComponent(CK_RTTI, reinterpret_cast(RD)); + } + + static VTableComponent MakeFunction(const CXXMethodDecl *MD) { + assert(!isa(MD) && + "Don't use MakeFunction with destructors!"); + + return VTableComponent(CK_FunctionPointer, + reinterpret_cast(MD)); + } + + static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_CompleteDtorPointer, + reinterpret_cast(DD)); + } + + static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_DeletingDtorPointer, + reinterpret_cast(DD)); + } + + static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { + assert(!isa(MD) && + "Don't use MakeUnusedFunction with destructors!"); + return VTableComponent(CK_UnusedFunctionPointer, + reinterpret_cast(MD)); + } + + static VTableComponent getFromOpaqueInteger(uint64_t I) { + return VTableComponent(I); + } + + /// getKind - Get the kind of this vtable component. + Kind getKind() const { + return (Kind)(Value & 0x7); + } + + int64_t getVCallOffset() const { + assert(getKind() == CK_VCallOffset && "Invalid component kind!"); + + return getOffset(); + } + + int64_t getVBaseOffset() const { + assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); + + return getOffset(); + } + + int64_t getOffsetToTop() const { + assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); + + return getOffset(); + } + + const CXXRecordDecl *getRTTIDecl() const { + assert(getKind() == CK_RTTI && "Invalid component kind!"); + + return reinterpret_cast(getPointer()); + } + + const CXXMethodDecl *getFunctionDecl() const { + assert(getKind() == CK_FunctionPointer); + + return reinterpret_cast(getPointer()); + } + + const CXXDestructorDecl *getDestructorDecl() const { + assert((getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); + + return reinterpret_cast(getPointer()); + } + + const CXXMethodDecl *getUnusedFunctionDecl() const { + assert(getKind() == CK_UnusedFunctionPointer); + + return reinterpret_cast(getPointer()); + } + +private: + VTableComponent(Kind ComponentKind, int64_t Offset) { + assert((ComponentKind == CK_VCallOffset || + ComponentKind == CK_VBaseOffset || + ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); + assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!"); + + Value = ((Offset << 3) | ComponentKind); + } + + VTableComponent(Kind ComponentKind, uintptr_t Ptr) { + assert((ComponentKind == CK_RTTI || + ComponentKind == CK_FunctionPointer || + ComponentKind == CK_CompleteDtorPointer || + ComponentKind == CK_DeletingDtorPointer || + ComponentKind == CK_UnusedFunctionPointer) && + "Invalid component kind!"); + + assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); + + Value = Ptr | ComponentKind; + } + + int64_t getOffset() const { + assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || + getKind() == CK_OffsetToTop) && "Invalid component kind!"); + + return Value >> 3; + } + + uintptr_t getPointer() const { + assert((getKind() == CK_RTTI || + getKind() == CK_FunctionPointer || + getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer || + getKind() == CK_UnusedFunctionPointer) && + "Invalid component kind!"); + + return static_cast(Value & ~7ULL); + } + + explicit VTableComponent(uint64_t Value) + : Value(Value) { } + + /// The kind is stored in the lower 3 bits of the value. For offsets, we + /// make use of the facts that classes can't be larger than 2^55 bytes, + /// so we store the offset in the lower part of the 61 bytes that remain. + /// (The reason that we're not simply using a PointerIntPair here is that we + /// need the offsets to be 64-bit, even when on a 32-bit machine). + int64_t Value; +}; + +/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. +struct VCallOffsetMap { + + typedef std::pair MethodAndOffsetPairTy; + + /// Offsets - Keeps track of methods and their offsets. + // FIXME: This should be a real map and not a vector. + llvm::SmallVector Offsets; + + /// MethodsCanShareVCallOffset - Returns whether two virtual member functions + /// can share the same vcall offset. + static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS); + +public: + /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the + /// add was successful, or false if there was already a member function with + /// the same signature in the map. + bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset); + + /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the + /// vtable address point) for the given virtual member function. + int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); + + // empty - Return whether the offset map is empty or not. + bool empty() const { return Offsets.empty(); } +}; + +static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + ASTContext &C = LHS->getASTContext(); // TODO: thread this down + CanQual + LT = C.getCanonicalType(LHS->getType()).getAs(), + RT = C.getCanonicalType(RHS->getType()).getAs(); + + // Fast-path matches in the canonical types. + if (LT == RT) return true; + + // Force the signatures to match. We can't rely on the overrides + // list here because there isn't necessarily an inheritance + // relationship between the two methods. + if (LT.getQualifiers() != RT.getQualifiers() || + LT->getNumArgs() != RT->getNumArgs()) + return false; + for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) + if (LT->getArgType(I) != RT->getArgType(I)) + return false; + return true; +} + +bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + assert(LHS->isVirtual() && "LHS must be virtual!"); + assert(RHS->isVirtual() && "LHS must be virtual!"); + + // A destructor can share a vcall offset with another destructor. + if (isa(LHS)) + return isa(RHS); + + // FIXME: We need to check more things here. + + // The methods must have the same name. + DeclarationName LHSName = LHS->getDeclName(); + DeclarationName RHSName = RHS->getDeclName(); + if (LHSName != RHSName) + return false; + + // And the same signatures. + return HasSameVirtualSignature(LHS, RHS); +} + +bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, + int64_t OffsetOffset) { + // Check if we can reuse an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return false; + } + + // Add the offset. + Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); + return true; +} + +int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { + // Look for an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return Offsets[I].second; + } + + assert(false && "Should always find a vcall offset offset!"); + return 0; +} + +/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. +class VCallAndVBaseOffsetBuilder { +public: + typedef llvm::DenseMap + VBaseOffsetOffsetsMapTy; + +private: + /// MostDerivedClass - The most derived class for which we're building vcall + /// and vbase offsets. + const CXXRecordDecl *MostDerivedClass; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// Components - vcall and vbase offset components + typedef llvm::SmallVector VTableComponentVectorTy; + VTableComponentVectorTy Components; + + /// VisitedVirtualBases - Visited virtual bases. + llvm::SmallPtrSet VisitedVirtualBases; + + /// VCallOffsets - Keeps track of vcall offsets. + VCallOffsetMap VCallOffsets; + + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, + /// relative to the address point. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + + /// FinalOverriders - The final overriders of the most derived class. + /// (Can be null when we're not building a vtable of the most derived class). + const FinalOverriders *Overriders; + + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the + /// given base subobject. + void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset); + + /// AddVCallOffsets - Add vcall offsets for the given base subobject. + void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); + + /// AddVBaseOffsets - Add vbase offsets for the given class. + void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); + + /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in + /// bytes, relative to the vtable address point. + int64_t getCurrentOffsetOffset() const; + +public: + VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *LayoutClass, + const FinalOverriders *Overriders, + BaseSubobject Base, bool BaseIsVirtual, + uint64_t OffsetInLayoutClass) + : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { + + // Add vcall and vbase offsets. + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); + } + + /// Methods for iterating over the components. + typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; + const_iterator components_begin() const { return Components.rbegin(); } + const_iterator components_end() const { return Components.rend(); } + + const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } +}; + +void +VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, + bool BaseIsVirtual, + uint64_t RealBaseOffset) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); + + // Itanium C++ ABI 2.5.2: + // ..in classes sharing a virtual table with a primary base class, the vcall + // and vbase offsets added by the derived class all come before the vcall + // and vbase offsets required by the base class, so that the latter may be + // laid out as required by the base class without regard to additions from + // the derived class(es). + + // (Since we're emitting the vcall and vbase offsets in reverse order, we'll + // emit them for the primary base first). + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); + + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset); + } + + AddVBaseOffsets(Base.getBase(), RealBaseOffset); + + // We only want to add vcall offsets for virtual bases. + if (BaseIsVirtual) + AddVCallOffsets(Base, RealBaseOffset); +} + +int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { + // OffsetIndex is the index of this vcall or vbase offset, relative to the + // vtable address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(int64_t)(3 + Components.size()); + + // FIXME: We shouldn't use / 8 here. + int64_t OffsetOffset = OffsetIndex * + (int64_t)Context.Target.getPointerWidth(0) / 8; + + return OffsetOffset; +} + +void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, + uint64_t VBaseOffset) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // Handle the primary base first. + // We only want to add vcall offsets if the base is non-virtual; a virtual + // primary base will have its vcall and vbase offsets emitted already. + if (PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) { + // Get the base offset of the primary base. + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), + VBaseOffset); + } + + // Add the vcall offsets. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + int64_t OffsetOffset = getCurrentOffsetOffset(); + + // Don't add a vcall offset if we already have one for this member function + // signature. + if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) + continue; + + int64_t Offset = 0; + + if (Overriders) { + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders->getOverrider(Base, MD); + + /// The vcall offset is the offset from the virtual base to the object + /// where the function was overridden. + // FIXME: We should not use / 8 here. + Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; + } + + Components.push_back(VTableComponent::MakeVCallOffset(Offset)); + } + + // And iterate over all non-virtual bases (ignoring the primary base). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + if (BaseDecl == PrimaryBase) + continue; + + // Get the base offset of this base. + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); + } +} + +void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass) { + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Add vbase offsets. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Check if this is a virtual base that we haven't visited before. + if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { + // FIXME: We shouldn't use / 8 here. + int64_t Offset = + (int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) - + OffsetInLayoutClass) / 8; + + // Add the vbase offset offset. + assert(!VBaseOffsetOffsets.count(BaseDecl) && + "vbase offset offset already exists!"); + + int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); + VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); + + Components.push_back(VTableComponent::MakeVBaseOffset(Offset)); + } + + // Check the base class looking for more vbase offsets. + AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); + } +} + +/// VTableBuilder - Class for building vtable layout information. +class VTableBuilder { +public: + /// PrimaryBasesSetVectorTy - A set vector of direct and indirect + /// primary bases. + typedef llvm::SmallSetVector + PrimaryBasesSetVectorTy; + + typedef llvm::DenseMap + VBaseOffsetOffsetsMapTy; + + typedef llvm::DenseMap + AddressPointsMapTy; + +private: + /// VTables - Global vtable information. + CodeGenVTables &VTables; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + /// MostDerivedClassOffset - If we're building a construction vtable, this + /// holds the offset from the layout class to the most derived class. + const uint64_t MostDerivedClassOffset; + + /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual + /// base. (This only makes sense when building a construction vtable). + bool MostDerivedClassIsVirtual; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// FinalOverriders - The final overriders of the most derived class. + const FinalOverriders Overriders; + + /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual + /// bases in this vtable. + llvm::DenseMap VCallOffsetsForVBases; + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for + /// the most derived class. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + + /// Components - The components of the vtable being built. + llvm::SmallVector Components; + + /// AddressPoints - Address points for the vtable being built. + AddressPointsMapTy AddressPoints; + + /// MethodInfo - Contains information about a method in a vtable. + /// (Used for computing 'this' pointer adjustment thunks. + struct MethodInfo { + /// BaseOffset - The base offset of this method. + const uint64_t BaseOffset; + + /// BaseOffsetInLayoutClass - The base offset in the layout class of this + /// method. + const uint64_t BaseOffsetInLayoutClass; + + /// VTableIndex - The index in the vtable that this method has. + /// (For destructors, this is the index of the complete destructor). + const uint64_t VTableIndex; + + MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, + uint64_t VTableIndex) + : BaseOffset(BaseOffset), + BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), + VTableIndex(VTableIndex) { } + + MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { } + }; + + typedef llvm::DenseMap MethodInfoMapTy; + + /// MethodInfoMap - The information for all methods in the vtable we're + /// currently building. + MethodInfoMapTy MethodInfoMap; + + typedef llvm::DenseMap VTableThunksMapTy; + + /// VTableThunks - The thunks by vtable index in the vtable currently being + /// built. + VTableThunksMapTy VTableThunks; + + typedef llvm::SmallVector ThunkInfoVectorTy; + typedef llvm::DenseMap ThunksMapTy; + + /// Thunks - A map that contains all the thunks needed for all methods in the + /// most derived class for which the vtable is currently being built. + ThunksMapTy Thunks; + + /// AddThunk - Add a thunk for the given method. + void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); + + /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the + /// part of the vtable we're currently building. + void ComputeThisAdjustments(); + + typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; + + /// PrimaryVirtualBases - All known virtual bases who are a primary base of + /// some other base. + VisitedVirtualBasesSetTy PrimaryVirtualBases; + + /// ComputeReturnAdjustment - Compute the return adjustment given a return + /// adjustment base offset. + ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); + + /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting + /// the 'this' pointer from the base subobject to the derived subobject. + BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const; + + /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the + /// given virtual member function, its offset in the layout class and its + /// final overrider. + ThisAdjustment + ComputeThisAdjustment(const CXXMethodDecl *MD, + uint64_t BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider); + + /// AddMethod - Add a single virtual member function to the vtable + /// components vector. + void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); + + /// IsOverriderUsed - Returns whether the overrider will ever be used in this + /// part of the vtable. + /// + /// Itanium C++ ABI 2.5.2: + /// + /// struct A { virtual void f(); }; + /// struct B : virtual public A { int i; }; + /// struct C : virtual public A { int j; }; + /// struct D : public B, public C {}; + /// + /// When B and C are declared, A is a primary base in each case, so although + /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this + /// adjustment is required and no thunk is generated. However, inside D + /// objects, A is no longer a primary base of C, so if we allowed calls to + /// C::f() to use the copy of A's vtable in the C subobject, we would need + /// to adjust this from C* to B::A*, which would require a third-party + /// thunk. Since we require that a call to C::f() first convert to A*, + /// C-in-D's copy of A's vtable is never referenced, so this is not + /// necessary. + bool IsOverriderUsed(const CXXMethodDecl *Overrider, + uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass) const; + + + /// AddMethods - Add the methods of this base subobject and all its + /// primary bases to the vtable components vector. + void AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases); + + // LayoutVTable - Layout the vtable for the given base class, including its + // secondary vtables and any vtables for virtual bases. + void LayoutVTable(); + + /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the + /// given base subobject, as well as all its secondary vtables. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual + /// in the layout class. + void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, + uint64_t OffsetInLayoutClass); + + /// LayoutSecondaryVTables - Layout the secondary vtables for the given base + /// subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, + uint64_t OffsetInLayoutClass); + + /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this + /// class hierarchy. + void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the + /// given base (excluding any primary bases). + void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// isBuildingConstructionVTable - Return whether this vtable builder is + /// building a construction vtable. + bool isBuildingConstructorVTable() const { + return MostDerivedClass != LayoutClass; + } + +public: + VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass) + : VTables(VTables), MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), + MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), + LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), + Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { + + LayoutVTable(); + } + + ThunksMapTy::const_iterator thunks_begin() const { + return Thunks.begin(); + } + + ThunksMapTy::const_iterator thunks_end() const { + return Thunks.end(); + } + + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } + + /// getNumVTableComponents - Return the number of components in the vtable + /// currently built. + uint64_t getNumVTableComponents() const { + return Components.size(); + } + + const uint64_t *vtable_components_data_begin() const { + return reinterpret_cast(Components.begin()); + } + + const uint64_t *vtable_components_data_end() const { + return reinterpret_cast(Components.end()); + } + + AddressPointsMapTy::const_iterator address_points_begin() const { + return AddressPoints.begin(); + } + + AddressPointsMapTy::const_iterator address_points_end() const { + return AddressPoints.end(); + } + + VTableThunksMapTy::const_iterator vtable_thunks_begin() const { + return VTableThunks.begin(); + } + + VTableThunksMapTy::const_iterator vtable_thunks_end() const { + return VTableThunks.end(); + } + + /// dumpLayout - Dump the vtable layout. + void dumpLayout(llvm::raw_ostream&); +}; + +void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { + assert(!isBuildingConstructorVTable() && + "Can't add thunks for construction vtable"); + + llvm::SmallVector &ThunksVector = Thunks[MD]; + + // Check if we have this thunk already. + if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != + ThunksVector.end()) + return; + + ThunksVector.push_back(Thunk); +} + +typedef llvm::SmallPtrSet OverriddenMethodsSetTy; + +/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all +/// the overridden methods that the function decl overrides. +static void +ComputeAllOverriddenMethods(const CXXMethodDecl *MD, + OverriddenMethodsSetTy& OverriddenMethods) { + assert(MD->isVirtual() && "Method is not virtual!"); + + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + OverriddenMethods.insert(OverriddenMD); + + ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods); + } +} + +void VTableBuilder::ComputeThisAdjustments() { + // Now go through the method info map and see if any of the methods need + // 'this' pointer adjustments. + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MethodInfo = I->second; + + // Ignore adjustments for unused function pointers. + uint64_t VTableIndex = MethodInfo.VTableIndex; + if (Components[VTableIndex].getKind() == + VTableComponent::CK_UnusedFunctionPointer) + continue; + + // Get the final overrider for this method. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(BaseSubobject(MD->getParent(), + MethodInfo.BaseOffset), MD); + + // Check if we need an adjustment at all. + if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { + // When a return thunk is needed by a derived class that overrides a + // virtual base, gcc uses a virtual 'this' adjustment as well. + // While the thunk itself might be needed by vtables in subclasses or + // in construction vtables, there doesn't seem to be a reason for using + // the thunk in this vtable. Still, we do so to match gcc. + if (VTableThunks.lookup(VTableIndex).Return.isEmpty()) + continue; + } + + ThisAdjustment ThisAdjustment = + ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); + + if (ThisAdjustment.isEmpty()) + continue; + + // Add it. + VTableThunks[VTableIndex].This = ThisAdjustment; + + if (isa(MD)) { + // Add an adjustment for the deleting destructor as well. + VTableThunks[VTableIndex + 1].This = ThisAdjustment; + } + } + + /// Clear the method info map. + MethodInfoMap.clear(); + + if (isBuildingConstructorVTable()) { + // We don't need to store thunk information for construction vtables. + return; + } + + for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(), + E = VTableThunks.end(); I != E; ++I) { + const VTableComponent &Component = Components[I->first]; + const ThunkInfo &Thunk = I->second; + const CXXMethodDecl *MD; + + switch (Component.getKind()) { + default: + llvm_unreachable("Unexpected vtable component kind!"); + case VTableComponent::CK_FunctionPointer: + MD = Component.getFunctionDecl(); + break; + case VTableComponent::CK_CompleteDtorPointer: + MD = Component.getDestructorDecl(); + break; + case VTableComponent::CK_DeletingDtorPointer: + // We've already added the thunk when we saw the complete dtor pointer. + continue; + } + + if (MD->getParent() == MostDerivedClass) + AddThunk(MD, Thunk); + } +} + +ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { + ReturnAdjustment Adjustment; + + if (!Offset.isEmpty()) { + if (Offset.VirtualBase) { + // Get the virtual base offset offset. + if (Offset.DerivedClass == MostDerivedClass) { + // We can get the offset offset directly from our map. + Adjustment.VBaseOffsetOffset = + VBaseOffsetOffsets.lookup(Offset.VirtualBase); + } else { + Adjustment.VBaseOffsetOffset = + VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, + Offset.VirtualBase); + } + } + + Adjustment.NonVirtual = Offset.NonVirtualOffset; + } + + return Adjustment; +} + +BaseOffset +VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const { + const CXXRecordDecl *BaseRD = Base.getBase(); + const CXXRecordDecl *DerivedRD = Derived.getBase(); + + CXXBasePaths Paths(/*FindAmbiguities=*/true, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + + if (!const_cast(DerivedRD)-> + isDerivedFrom(const_cast(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return BaseOffset(); + } + + // We have to go through all the paths, and see which one leads us to the + // right base subobject. + for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); + I != E; ++I) { + BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); + + // FIXME: Should not use * 8 here. + uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8; + + if (Offset.VirtualBase) { + // If we have a virtual base class, the non-virtual offset is relative + // to the virtual base class offset. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + /// Get the virtual base offset, relative to the most derived class + /// layout. + OffsetToBaseSubobject += + LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); + } else { + // Otherwise, the non-virtual offset is relative to the derived class + // offset. + OffsetToBaseSubobject += Derived.getBaseOffset(); + } + + // Check if this path gives us the right base subobject. + if (OffsetToBaseSubobject == Base.getBaseOffset()) { + // Since we're going from the base class _to_ the derived class, we'll + // invert the non-virtual offset here. + Offset.NonVirtualOffset = -Offset.NonVirtualOffset; + return Offset; + } + } + + return BaseOffset(); +} + +ThisAdjustment +VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, + uint64_t BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) { + // Ignore adjustments for pure virtual member functions. + if (Overrider.Method->isPure()) + return ThisAdjustment(); + + BaseSubobject OverriddenBaseSubobject(MD->getParent(), + BaseOffsetInLayoutClass); + + BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), + Overrider.Offset); + + // Compute the adjustment offset. + BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, + OverriderBaseSubobject); + if (Offset.isEmpty()) + return ThisAdjustment(); + + ThisAdjustment Adjustment; + + if (Offset.VirtualBase) { + // Get the vcall offset map for this virtual base. + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; + + if (VCallOffsets.empty()) { + // We don't have vcall offsets for this virtual base, go ahead and + // build them. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, + /*FinalOverriders=*/0, + BaseSubobject(Offset.VirtualBase, 0), + /*BaseIsVirtual=*/true, + /*OffsetInLayoutClass=*/0); + + VCallOffsets = Builder.getVCallOffsets(); + } + + Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); + } + + // Set the non-virtual part of the adjustment. + Adjustment.NonVirtual = Offset.NonVirtualOffset; + + return Adjustment; +} + +void +VTableBuilder::AddMethod(const CXXMethodDecl *MD, + ReturnAdjustment ReturnAdjustment) { + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + assert(ReturnAdjustment.isEmpty() && + "Destructor can't have return adjustment!"); + + // Add both the complete destructor and the deleting destructor. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); + } else { + // Add the return adjustment if necessary. + if (!ReturnAdjustment.isEmpty()) + VTableThunks[Components.size()].Return = ReturnAdjustment; + + // Add the function. + Components.push_back(VTableComponent::MakeFunction(MD)); + } +} + +/// OverridesIndirectMethodInBase - Return whether the given member function +/// overrides any methods in the set of given bases. +/// Unlike OverridesMethodInBase, this checks "overriders of overriders". +/// For example, if we have: +/// +/// struct A { virtual void f(); } +/// struct B : A { virtual void f(); } +/// struct C : B { virtual void f(); } +/// +/// OverridesIndirectMethodInBase will return true if given C::f as the method +/// and { A } as the set of bases. +static bool +OverridesIndirectMethodInBases(const CXXMethodDecl *MD, + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + if (Bases.count(MD->getParent())) + return true; + + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // Check "indirect overriders". + if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) + return true; + } + + return false; +} + +bool +VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, + uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass) const { + // If the base and the first base in the primary base chain have the same + // offsets, then this overrider will be used. + if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) + return true; + + // We know now that Base (or a direct or indirect base of it) is a primary + // base in part of the class hierarchy, but not a primary base in the most + // derived class. + + // If the overrider is the first base in the primary base chain, we know + // that the overrider will be used. + if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) + return true; + + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + + const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; + PrimaryBases.insert(RD); + + // Now traverse the base chain, starting with the first base, until we find + // the base that is no longer a primary base. + while (true) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Now check if this is the primary base that is not a primary base in the + // most derived class. + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + FirstBaseOffsetInLayoutClass) { + // We found it, stop walking the chain. + break; + } + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + } + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); + + RD = PrimaryBase; + } + + // If the final overrider is an override of one of the primary bases, + // then we know that it will be used. + return OverridesIndirectMethodInBases(Overrider, PrimaryBases); +} + +/// FindNearestOverriddenMethod - Given a method, returns the overridden method +/// from the nearest base. Returns null if no method was found. +static const CXXMethodDecl * +FindNearestOverriddenMethod(const CXXMethodDecl *MD, + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + OverriddenMethodsSetTy OverriddenMethods; + ComputeAllOverriddenMethods(MD, OverriddenMethods); + + for (int I = Bases.size(), E = 0; I != E; --I) { + const CXXRecordDecl *PrimaryBase = Bases[I - 1]; + + // Now check the overriden methods. + for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(), + E = OverriddenMethods.end(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // We found our overridden method. + if (OverriddenMD->getParent() == PrimaryBase) + return OverriddenMD; + } + } + + return 0; +} + +void +VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + uint64_t PrimaryBaseOffset; + uint64_t PrimaryBaseOffsetInLayoutClass; + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; + } + + AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, + FirstBaseOffsetInLayoutClass, PrimaryBases); + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); + } + + // Now go through all virtual member functions and add them. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(Base, MD); + + // Check if this virtual member function overrides a method in a primary + // base. If this is the case, and the return type doesn't require adjustment + // then we can just use the member function from the primary base. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, PrimaryBases)) { + if (ComputeReturnAdjustmentBaseOffset(Context, MD, + OverriddenMD).isEmpty()) { + // Replace the method info of the overridden method with our own + // method. + assert(MethodInfoMap.count(OverriddenMD) && + "Did not find the overridden method!"); + MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; + + MethodInfo MethodInfo(Base.getBaseOffset(), + BaseOffsetInLayoutClass, + OverriddenMethodInfo.VTableIndex); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + MethodInfoMap.erase(OverriddenMD); + + // If the overridden method exists in a virtual base class or a direct + // or indirect base class of a virtual base class, we need to emit a + // thunk if we ever have a class hierarchy where the base class is not + // a primary base in the complete object. + if (!isBuildingConstructorVTable() && OverriddenMD != MD) { + // Compute the this adjustment. + ThisAdjustment ThisAdjustment = + ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, + Overrider); + + if (ThisAdjustment.VCallOffsetOffset && + Overrider.Method->getParent() == MostDerivedClass) { + // This is a virtual thunk for the most derived class, add it. + AddThunk(Overrider.Method, + ThunkInfo(ThisAdjustment, ReturnAdjustment())); + } + } + + continue; + } + } + + // Insert the method info for this method. + MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, + Components.size()); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + + // Check if this overrider is going to be used. + const CXXMethodDecl *OverriderMD = Overrider.Method; + if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, + FirstBaseInPrimaryBaseChain, + FirstBaseOffsetInLayoutClass)) { + Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); + continue; + } + + // Check if this overrider needs a return adjustment. + BaseOffset ReturnAdjustmentOffset = + Overriders.getReturnAdjustmentOffset(Base, MD); + + ReturnAdjustment ReturnAdjustment = + ComputeReturnAdjustment(ReturnAdjustmentOffset); + + AddMethod(Overrider.Method, ReturnAdjustment); + } +} + +void VTableBuilder::LayoutVTable() { + LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0), + /*BaseIsMorallyVirtual=*/false, + MostDerivedClassIsVirtual, + MostDerivedClassOffset); + + VisitedVirtualBasesSetTy VBases; + + // Determine the primary virtual bases. + DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, + VBases); + VBases.clear(); + + LayoutVTablesForVirtualBases(MostDerivedClass, VBases); +} + +void +VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, + uint64_t OffsetInLayoutClass) { + assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); + + // Add vcall and vbase offsets for this vtable. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, + Base, BaseIsVirtualInLayoutClass, + OffsetInLayoutClass); + Components.append(Builder.components_begin(), Builder.components_end()); + + // Check if we need to add these vcall offsets. + if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) { + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; + + if (VCallOffsets.empty()) + VCallOffsets = Builder.getVCallOffsets(); + } + + // If we're laying out the most derived class we want to keep track of the + // virtual base class offset offsets. + if (Base.getBase() == MostDerivedClass) + VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); + + // Add the offset to top. + // FIXME: We should not use / 8 here. + int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - + MostDerivedClassOffset) / 8; + Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); + + // Next, add the RTTI. + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); + + uint64_t AddressPoint = Components.size(); + + // Now go through all virtual member functions and add them. + PrimaryBasesSetVectorTy PrimaryBases; + AddMethods(Base, OffsetInLayoutClass, Base.getBase(), OffsetInLayoutClass, + PrimaryBases); + + // Compute 'this' pointer adjustments. + ComputeThisAdjustments(); + + // Add all address points. + const CXXRecordDecl *RD = Base.getBase(); + while (true) { + AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass), + AddressPoint)); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.getPrimaryBaseWasVirtual()) { + // Check if this virtual primary base is a primary base in the layout + // class. If it's not, we don't want to add it. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + OffsetInLayoutClass) { + // We don't want to add this class (or any of its primary bases). + break; + } + } + + RD = PrimaryBase; + } + + // Layout secondary vtables. + LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); +} + +void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + uint64_t OffsetInLayoutClass) { + // Itanium C++ ABI 2.5.2: + // Following the primary virtual table of a derived class are secondary + // virtual tables for each of its proper base classes, except any primary + // base(s) with which it shares its primary virtual table. + + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + // Ignore virtual bases, we'll emit them later. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Ignore bases that don't have a vtable. + if (!BaseDecl->isDynamicClass()) + continue; + + if (isBuildingConstructorVTable()) { + // Itanium C++ ABI 2.6.4: + // Some of the base class subobjects may not need construction virtual + // tables, which will therefore not be present in the construction + // virtual table group, even though the subobject virtual tables are + // present in the main virtual table group for the complete object. + if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) + continue; + } + + // Get the base offset of this base. + uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); + uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; + + uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset; + + // Don't emit a secondary vtable for a primary base. We might however want + // to emit secondary vtables for other bases of this base. + if (BaseDecl == PrimaryBase) { + LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, BaseOffsetInLayoutClass); + continue; + } + + // Layout the primary vtable (and any secondary vtables) for this base. + LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, + /*BaseIsVirtualInLayoutClass=*/false, + BaseOffsetInLayoutClass); + } +} + +void +VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Check if this base has a primary base. + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + + // Check if it's virtual. + if (Layout.getPrimaryBaseWasVirtual()) { + bool IsPrimaryVirtualBase = true; + + if (isBuildingConstructorVTable()) { + // Check if the base is actually a primary base in the class we use for + // layout. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + uint64_t PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); + + // We know that the base is not a primary base in the layout class if + // the base offsets are different. + if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) + IsPrimaryVirtualBase = false; + } + + if (IsPrimaryVirtualBase) + PrimaryVirtualBases.insert(PrimaryBase); + } + } + + // Traverse bases, looking for more primary virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseOffsetInLayoutClass; + + if (I->isVirtual()) { + if (!VBases.insert(BaseDecl)) + continue; + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + BaseOffsetInLayoutClass = LayoutClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffsetInLayoutClass = + OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); + } + + DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); + } +} + +void +VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + // Itanium C++ ABI 2.5.2: + // Then come the virtual base virtual tables, also in inheritance graph + // order, and again excluding primary bases (which share virtual tables with + // the classes for which they are primary). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Check if this base needs a vtable. (If it's virtual, not a primary base + // of some other class, and we haven't visited it before). + if (I->isVirtual() && BaseDecl->isDynamicClass() && + !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + uint64_t BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + uint64_t BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsMorallyVirtual=*/true, + /*BaseIsVirtualInLayoutClass=*/true, + BaseOffsetInLayoutClass); + } + + // We only need to check the base for virtual base vtables if it actually + // has virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVTablesForVirtualBases(BaseDecl, VBases); + } +} + +/// dumpLayout - Dump the vtable layout. +void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { + + if (isBuildingConstructorVTable()) { + Out << "Construction vtable for ('"; + Out << MostDerivedClass->getQualifiedNameAsString() << "', "; + // FIXME: Don't use / 8 . + Out << MostDerivedClassOffset / 8 << ") in '"; + Out << LayoutClass->getQualifiedNameAsString(); + } else { + Out << "Vtable for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); + } + Out << "' (" << Components.size() << " entries).\n"; + + // Iterate through the address points and insert them into a new map where + // they are keyed by the index and not the base object. + // Since an address point can be shared by multiple subobjects, we use an + // STL multimap. + std::multimap AddressPointsByIndex; + for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), + E = AddressPoints.end(); I != E; ++I) { + const BaseSubobject& Base = I->first; + uint64_t Index = I->second; + + AddressPointsByIndex.insert(std::make_pair(Index, Base)); + } + + for (unsigned I = 0, E = Components.size(); I != E; ++I) { + uint64_t Index = I; + + Out << llvm::format("%4d | ", I); + + const VTableComponent &Component = Components[I]; + + // Dump the component. + switch (Component.getKind()) { + + case VTableComponent::CK_VCallOffset: + Out << "vcall_offset (" << Component.getVCallOffset() << ")"; + break; + + case VTableComponent::CK_VBaseOffset: + Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; + break; + + case VTableComponent::CK_OffsetToTop: + Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; + break; + + case VTableComponent::CK_RTTI: + Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; + break; + + case VTableComponent::CK_FunctionPointer: { + const CXXMethodDecl *MD = Component.getFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << Str; + if (MD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this function pointer has a return adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "\n [return adjustment: "; + Out << Thunk.Return.NonVirtual << " non-virtual"; + + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } + + Out << ']'; + } + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } + + break; + } + + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { + bool IsComplete = + Component.getKind() == VTableComponent::CK_CompleteDtorPointer; + + const CXXDestructorDecl *DD = Component.getDestructorDecl(); + + Out << DD->getQualifiedNameAsString(); + if (IsComplete) + Out << "() [complete]"; + else + Out << "() [deleting]"; + + if (DD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this destructor has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } + + break; + } + + case VTableComponent::CK_UnusedFunctionPointer: { + const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << "[unused] " << Str; + if (MD->isPure()) + Out << " [pure]"; + } + + } + + Out << '\n'; + + // Dump the next address point. + uint64_t NextIndex = Index + 1; + if (AddressPointsByIndex.count(NextIndex)) { + if (AddressPointsByIndex.count(NextIndex) == 1) { + const BaseSubobject &Base = + AddressPointsByIndex.find(NextIndex)->second; + + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); + Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; + } else { + uint64_t BaseOffset = + AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); + + // We store the class names in a set to get a stable order. + std::set ClassNames; + for (std::multimap::const_iterator I = + AddressPointsByIndex.lower_bound(NextIndex), E = + AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { + assert(I->second.getBaseOffset() == BaseOffset && + "Invalid base offset!"); + const CXXRecordDecl *RD = I->second.getBase(); + ClassNames.insert(RD->getQualifiedNameAsString()); + } + + for (std::set::const_iterator I = ClassNames.begin(), + E = ClassNames.end(); I != E; ++I) { + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << *I; + Out << ", " << BaseOffset / 8 << ") vtable address --\n"; + } + } + } + } + + Out << '\n'; + + if (isBuildingConstructorVTable()) + return; + + if (MostDerivedClass->getNumVBases()) { + // We store the virtual base class names and their offsets in a map to get + // a stable order. + + std::map ClassNamesAndOffsets; + for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), + E = VBaseOffsetOffsets.end(); I != E; ++I) { + std::string ClassName = I->first->getQualifiedNameAsString(); + int64_t OffsetOffset = I->second; + ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); + } + + Out << "Virtual base offset offsets for '"; + Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; + Out << ClassNamesAndOffsets.size(); + Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; + + for (std::map::const_iterator I = + ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); + I != E; ++I) + Out << " " << I->first << " | " << I->second << '\n'; + + Out << "\n"; + } + + if (!Thunks.empty()) { + // We store the method names in a map to get a stable order. + std::map MethodNamesAndDecls; + + for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end(); + I != E; ++I) { + const CXXMethodDecl *MD = I->first; + std::string MethodName = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + + MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); + } + + for (std::map::const_iterator I = + MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); + I != E; ++I) { + const std::string &MethodName = I->first; + const CXXMethodDecl *MD = I->second; + + ThunkInfoVectorTy ThunksVector = Thunks[MD]; + std::sort(ThunksVector.begin(), ThunksVector.end()); + + Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); + Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; + + for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { + const ThunkInfo &Thunk = ThunksVector[I]; + + Out << llvm::format("%4d | ", I); + + // If this function pointer has a return pointer adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "return adjustment: " << Thunk.This.NonVirtual; + Out << " non-virtual"; + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } + + if (!Thunk.This.isEmpty()) + Out << "\n "; + } + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + } + + Out << '\n'; + } + + Out << '\n'; + + } + } +} + +} + +void CodeGenVTables::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!"); + + // 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); + } + + // Collect all the primary bases, so we can check whether methods override + // a method from the base. + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + for (ASTRecordLayout::primary_base_info_iterator + I = Layout.primary_base_begin(), E = Layout.primary_base_end(); + I != E; ++I) + PrimaryBases.insert((*I).getBase()); + + 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; + + // Check if this method overrides a method in the primary base. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, PrimaryBases)) { + // Check if converting from the return type of the method to the + // return type of the overridden method requires conversion. + if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, + OverriddenMD).isEmpty()) { + // This index is shared between the index in the vtable of the primary + // base class. + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + const CXXDestructorDecl *OverriddenDD = + cast(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. + continue; + } + } + + if (const CXXDestructorDecl *DD = dyn_cast(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; +} + +uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { + llvm::DenseMap::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 CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) { + MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); + if (I != MethodVTableIndices.end()) + return I->second; + + const CXXRecordDecl *RD = cast(GD.getDecl())->getParent(); + + ComputeMethodVTableIndices(RD); + + I = MethodVTableIndices.find(GD); + assert(I != MethodVTableIndices.end() && "Did not find index!"); + return I->second; +} + +int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { + ClassPairTy ClassPair(RD, VBase); + + VirtualBaseClassOffsetOffsetsMapTy::iterator I = + VirtualBaseClassOffsetOffsets.find(ClassPair); + if (I != VirtualBaseClassOffsetOffsets.end()) + return I->second; + + VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, + BaseSubobject(RD, 0), + /*BaseIsVirtual=*/false, + /*OffsetInLayoutClass=*/0); + + for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { + // Insert all types. + ClassPairTy ClassPair(RD, I->first); + + VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); + } + + I = VirtualBaseClassOffsetOffsets.find(ClassPair); + assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); + + return I->second; +} + +uint64_t +CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) { + assert(AddressPoints.count(std::make_pair(RD, Base)) && + "Did not find address point!"); + + uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base)); + assert(AddressPoint && "Address point must not be zero!"); + + return AddressPoint; +} + +llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkInfo &Thunk) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Compute the mangled name. + llvm::SmallString<256> Name; + if (const CXXDestructorDecl* DD = dyn_cast(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This, + Name); + else + getMangleContext().mangleThunk(MD, Thunk, Name); + + const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, + llvm::Value *Ptr, + int64_t NonVirtualAdjustment, + int64_t VirtualAdjustment) { + if (!NonVirtualAdjustment && !VirtualAdjustment) + return Ptr; + + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + + llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); + + if (NonVirtualAdjustment) { + // Do the non-virtual adjustment. + V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment); + } + + if (VirtualAdjustment) { + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + // Do the virtual adjustment. + llvm::Value *VTablePtrPtr = + CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo()); + + llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr); + + llvm::Value *OffsetPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment); + + OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo()); + + // Load the adjustment offset from the vtable. + llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr); + + // Adjust our pointer. + V = CGF.Builder.CreateInBoundsGEP(V, Offset); + } + + // Cast back to the original type. + return CGF.Builder.CreateBitCast(V, Ptr->getType()); +} + +void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, + const ThunkInfo &Thunk) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const FunctionProtoType *FPT = MD->getType()->getAs(); + QualType ResultType = FPT->getResultType(); + QualType ThisType = MD->getThisType(getContext()); + + FunctionArgList FunctionArgs; + + // FIXME: It would be nice if more of this code could be shared with + // CodeGenFunction::GenerateCode. + + // Create the implicit 'this' parameter declaration. + CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, + MD->getLocation(), + &getContext().Idents.get("this"), + ThisType); + + // Add the 'this' parameter. + FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); + + // Add the rest of the parameters. + for (FunctionDecl::param_const_iterator I = MD->param_begin(), + E = MD->param_end(); I != E; ++I) { + ParmVarDecl *Param = *I; + + FunctionArgs.push_back(std::make_pair(Param, Param->getType())); + } + + StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation()); + + // Adjust the 'this' pointer if necessary. + llvm::Value *AdjustedThisPtr = + PerformTypeAdjustment(*this, LoadCXXThis(), + Thunk.This.NonVirtual, + Thunk.This.VCallOffsetOffset); + + CallArgList CallArgs; + + // Add our adjusted 'this' pointer. + CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType)); + + // Add the rest of the parameters. + for (FunctionDecl::param_const_iterator I = MD->param_begin(), + E = MD->param_end(); I != E; ++I) { + ParmVarDecl *Param = *I; + QualType ArgType = Param->getType(); + + // FIXME: Declaring a DeclRefExpr on the stack is kinda icky. + DeclRefExpr ArgExpr(Param, ArgType.getNonReferenceType(), SourceLocation()); + CallArgs.push_back(std::make_pair(EmitCallArg(&ArgExpr, ArgType), ArgType)); + } + + // Get our callee. + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); + + const CGFunctionInfo &FnInfo = + CGM.getTypes().getFunctionInfo(ResultType, CallArgs, + FPT->getExtInfo()); + + // Now emit our call. + RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD); + + if (!Thunk.Return.isEmpty()) { + // Emit the return adjustment. + bool NullCheckValue = !ResultType->isReferenceType(); + + llvm::BasicBlock *AdjustNull = 0; + llvm::BasicBlock *AdjustNotNull = 0; + llvm::BasicBlock *AdjustEnd = 0; + + llvm::Value *ReturnValue = RV.getScalarVal(); + + if (NullCheckValue) { + AdjustNull = createBasicBlock("adjust.null"); + AdjustNotNull = createBasicBlock("adjust.notnull"); + AdjustEnd = createBasicBlock("adjust.end"); + + llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue); + Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull); + EmitBlock(AdjustNotNull); + } + + ReturnValue = PerformTypeAdjustment(*this, ReturnValue, + Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + if (NullCheckValue) { + Builder.CreateBr(AdjustEnd); + EmitBlock(AdjustNull); + Builder.CreateBr(AdjustEnd); + EmitBlock(AdjustEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(ReturnValue, AdjustNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), + AdjustNull); + ReturnValue = PHI; + } + + RV = RValue::get(ReturnValue); + } + + if (!ResultType->isVoidType()) + EmitReturnOfRValue(RV, ResultType); + + FinishFunction(); + + // Destroy the 'this' declaration. + CXXThisDecl->Destroy(getContext()); + + // Set the right linkage. + Fn->setLinkage(CGM.getFunctionLinkage(MD)); + + // Set the right visibility. + CGM.setGlobalVisibility(Fn, MD); +} + +void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) +{ + llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Strip off a bitcast if we got one back. + if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { + assert(CE->getOpcode() == llvm::Instruction::BitCast); + Entry = CE->getOperand(0); + } + + // There's already a declaration with the same name, check if it has the same + // type or if we need to replace it. + if (cast(Entry)->getType()->getElementType() != + CGM.getTypes().GetFunctionTypeForVTable(MD)) { + llvm::GlobalValue *OldThunkFn = cast(Entry); + + // If the types mismatch then we have to rewrite the definition. + assert(OldThunkFn->isDeclaration() && + "Shouldn't replace non-declaration"); + + // Remove the name from the old thunk function and get a new thunk. + OldThunkFn->setName(llvm::StringRef()); + Entry = CGM.GetAddrOfThunk(GD, Thunk); + + // If needed, replace the old thunk with a bitcast. + if (!OldThunkFn->use_empty()) { + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(Entry, OldThunkFn->getType()); + OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl); + } + + // Remove the old thunk. + OldThunkFn->eraseFromParent(); + } + + // Actually generate the thunk body. + llvm::Function *ThunkFn = cast(Entry); + CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk); +} + +void CodeGenVTables::EmitThunks(GlobalDecl GD) +{ + const CXXMethodDecl *MD = + cast(GD.getDecl())->getCanonicalDecl(); + + // We don't need to generate thunks for the base destructor. + if (isa(MD) && GD.getDtorType() == Dtor_Base) + return; + + const CXXRecordDecl *RD = MD->getParent(); + + // Compute VTable related info for this class. + ComputeVTableRelatedInformation(RD); + + ThunksMapTy::const_iterator I = Thunks.find(MD); + if (I == Thunks.end()) { + // We did not find a thunk for this method. + return; + } + + const ThunkInfoVectorTy &ThunkInfoVector = I->second; + for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I) + EmitThunk(GD, ThunkInfoVector[I]); +} + +void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { + uint64_t *&LayoutData = VTableLayoutMap[RD]; + + // Check if we've computed this information before. + if (LayoutData) + return; + + VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + + // Add the VTable layout. + uint64_t NumVTableComponents = Builder.getNumVTableComponents(); + LayoutData = new uint64_t[NumVTableComponents + 1]; + + // Store the number of components. + LayoutData[0] = NumVTableComponents; + + // Store the components. + std::copy(Builder.vtable_components_data_begin(), + Builder.vtable_components_data_end(), + &LayoutData[1]); + + // Add the known thunks. + Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); + + // Add the thunks needed in this vtable. + assert(!VTableThunksMap.count(RD) && + "Thunks already exists for this vtable!"); + + VTableThunksTy &VTableThunks = VTableThunksMap[RD]; + VTableThunks.append(Builder.vtable_thunks_begin(), + Builder.vtable_thunks_end()); + + // Sort them. + std::sort(VTableThunks.begin(), VTableThunks.end()); + + // Add the address points. + for (VTableBuilder::AddressPointsMapTy::const_iterator I = + Builder.address_points_begin(), E = Builder.address_points_end(); + I != E; ++I) { + + uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)]; + + // Check if we already have the address points for this base. + assert(!AddressPoint && "Address point already exists for this base!"); + + AddressPoint = I->second; + } + + // If we don't have the vbase information for this class, insert it. + // getVirtualBaseOffsetOffset will compute it separately without computing + // the rest of the vtable related information. + if (!RD->getNumVBases()) + return; + + const RecordType *VBaseRT = + RD->vbases_begin()->getType()->getAs(); + const CXXRecordDecl *VBase = cast(VBaseRT->getDecl()); + + if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) + return; + + for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { + // Insert all types. + ClassPairTy ClassPair(RD, I->first); + + VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); + } +} + +llvm::Constant * +CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, + const uint64_t *Components, + unsigned NumComponents, + const VTableThunksTy &VTableThunks) { + llvm::SmallVector Inits; + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + + const llvm::Type *PtrDiffTy = + CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); + + QualType ClassType = CGM.getContext().getTagDeclType(RD); + llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType); + + unsigned NextVTableThunkIndex = 0; + + llvm::Constant* PureVirtualFn = 0; + + for (unsigned I = 0; I != NumComponents; ++I) { + VTableComponent Component = + VTableComponent::getFromOpaqueInteger(Components[I]); + + llvm::Constant *Init = 0; + + switch (Component.getKind()) { + case VTableComponent::CK_VCallOffset: + Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset()); + Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + break; + case VTableComponent::CK_VBaseOffset: + Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset()); + Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + break; + case VTableComponent::CK_OffsetToTop: + Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop()); + Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); + break; + case VTableComponent::CK_RTTI: + Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy); + break; + case VTableComponent::CK_FunctionPointer: + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { + GlobalDecl GD; + + // Get the right global decl. + switch (Component.getKind()) { + default: + llvm_unreachable("Unexpected vtable component kind"); + case VTableComponent::CK_FunctionPointer: + GD = Component.getFunctionDecl(); + break; + case VTableComponent::CK_CompleteDtorPointer: + GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete); + break; + case VTableComponent::CK_DeletingDtorPointer: + GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting); + break; + } + + if (cast(GD.getDecl())->isPure()) { + // We have a pure virtual member function. + if (!PureVirtualFn) { + const llvm::FunctionType *Ty = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), + /*isVarArg=*/false); + PureVirtualFn = + CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"); + PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn, + Int8PtrTy); + } + + Init = PureVirtualFn; + } else { + // Check if we should use a thunk. + if (NextVTableThunkIndex < VTableThunks.size() && + VTableThunks[NextVTableThunkIndex].first == I) { + const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second; + + Init = CGM.GetAddrOfThunk(GD, Thunk); + + NextVTableThunkIndex++; + } else { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(MD); + + Init = CGM.GetAddrOfFunction(GD, Ty); + } + + Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + } + break; + } + + case VTableComponent::CK_UnusedFunctionPointer: + Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); + break; + }; + + Inits.push_back(Init); + } + + llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); + return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size()); +} + +/// GetGlobalVariable - Will return a global variable of the given type. +/// If a variable with a different type already exists then a new variable +/// with the right type will be created. +/// FIXME: We should move this to CodeGenModule and rename it to something +/// better and then use it in CGVTT and CGRTTI. +static llvm::GlobalVariable * +GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, + const llvm::Type *Ty, + llvm::GlobalValue::LinkageTypes Linkage) { + + llvm::GlobalVariable *GV = Module.getNamedGlobal(Name); + llvm::GlobalVariable *OldGV = 0; + + if (GV) { + // Check if the variable has the right type. + if (GV->getType()->getElementType() == Ty) + return GV; + + assert(GV->isDeclaration() && "Declaration has wrong type!"); + + OldGV = GV; + } + + // Create a new variable. + GV = new llvm::GlobalVariable(Module, Ty, /*isConstant=*/true, + Linkage, 0, Name); + + if (OldGV) { + // Replace occurrences of the old variable if needed. + GV->takeName(OldGV); + + if (!OldGV->use_empty()) { + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); + } + + OldGV->eraseFromParent(); + } + + return GV; +} + +llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXVTable(RD, OutName); + llvm::StringRef Name = OutName.str(); + + ComputeVTableRelatedInformation(RD); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD)); + + return GetGlobalVariable(CGM.getModule(), Name, ArrayType, + llvm::GlobalValue::ExternalLinkage); +} + +void +CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + // Dump the vtable layout if necessary. + if (CGM.getLangOptions().DumpVTableLayouts) { + VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + + Builder.dumpLayout(llvm::errs()); + } + + assert(VTableThunksMap.count(RD) && + "No thunk status for this record decl!"); + + const VTableThunksTy& Thunks = VTableThunksMap[RD]; + + // Create and set the initializer. + llvm::Constant *Init = + CreateVTableInitializer(RD, getVTableComponentsData(RD), + getNumVTableComponents(RD), Thunks); + VTable->setInitializer(Init); + + // Set the correct linkage. + VTable->setLinkage(Linkage); +} + +llvm::GlobalVariable * +CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, + const BaseSubobject &Base, + bool BaseIsVirtual, + VTableAddressPointsMapTy& AddressPoints) { + VTableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(), + /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD); + + // Dump the vtable layout if necessary. + if (CGM.getLangOptions().DumpVTableLayouts) + Builder.dumpLayout(llvm::errs()); + + // Add the address points. + AddressPoints.insert(Builder.address_points_begin(), + Builder.address_points_end()); + + // Get the mangled construction vtable name. + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, + Base.getBase(), OutName); + llvm::StringRef Name = OutName.str(); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents()); + + // Create the variable that will hold the construction vtable. + llvm::GlobalVariable *VTable = + GetGlobalVariable(CGM.getModule(), Name, ArrayType, + llvm::GlobalValue::InternalLinkage); + + // Add the thunks. + VTableThunksTy VTableThunks; + VTableThunks.append(Builder.vtable_thunks_begin(), + Builder.vtable_thunks_end()); + + // Sort them. + std::sort(VTableThunks.begin(), VTableThunks.end()); + + // Create and set the initializer. + llvm::Constant *Init = + CreateVTableInitializer(Base.getBase(), + Builder.vtable_components_data_begin(), + Builder.getNumVTableComponents(), VTableThunks); + VTable->setInitializer(Init); + + return VTable; +} + +void +CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + llvm::GlobalVariable *&VTable = VTables[RD]; + if (VTable) { + assert(VTable->getInitializer() && "VTable doesn't have a definition!"); + return; + } + + VTable = GetAddrOfVTable(RD); + EmitVTableDefinition(VTable, Linkage, RD); + + GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); + + // If this is the magic class __cxxabiv1::__fundamental_type_info, + // we will emit the typeinfo for the fundamental types. This is the + // same behaviour as GCC. + const DeclContext *DC = RD->getDeclContext(); + if (RD->getIdentifier() && + RD->getIdentifier()->isStr("__fundamental_type_info") && + isa(DC) && + cast(DC)->getIdentifier() && + cast(DC)->getIdentifier()->isStr("__cxxabiv1") && + DC->getParent()->isTranslationUnit()) + CGM.EmitFundamentalRTTIDescriptors(); +} + +void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const CXXRecordDecl *RD = MD->getParent(); + + // If the class doesn't have a vtable we don't need to emit one. + if (!RD->isDynamicClass()) + return; + + // Check if we need to emit thunks for this function. + if (MD->isVirtual()) + EmitThunks(GD); + + // Get the key function. + const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); + + TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind(); + TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind(); + + if (KeyFunction) { + // We don't have the right key function. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) + return; + } else { + // If we have no key funcion and this is a explicit instantiation declaration, + // we will produce a vtable at the explicit instantiation. We don't need one + // here. + if (RDKind == clang::TSK_ExplicitInstantiationDeclaration) + return; + + // If this is an explicit instantiation of a method, we don't need a vtable. + // Since we have no key function, we will emit the vtable when we see + // a use, and just defining a function is not an use. + if (RDKind == TSK_ImplicitInstantiation && + MDKind == TSK_ExplicitInstantiationDefinition) + return; + } + + if (VTables.count(RD)) + return; + + if (RDKind == TSK_ImplicitInstantiation) + CGM.DeferredVTables.push_back(RD); + else + GenerateClassData(CGM.getVTableLinkage(RD), RD); +} diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h new file mode 100644 index 0000000..6c18ca8 --- /dev/null +++ b/lib/CodeGen/CGVTables.h @@ -0,0 +1,368 @@ +//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of virtual tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGVTABLE_H +#define CLANG_CODEGEN_CGVTABLE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/GlobalVariable.h" +#include "GlobalDecl.h" + +namespace clang { + class CXXRecordDecl; + +namespace CodeGen { + class CodeGenModule; + +/// ReturnAdjustment - A return adjustment. +struct ReturnAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VBaseOffsetOffset - The offset (in bytes), relative to the address point + /// of the virtual base class offset. + int64_t VBaseOffsetOffset; + + ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } + + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; + } + + friend bool operator<(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset; + } +}; + +/// ThisAdjustment - A 'this' pointer adjustment. +struct ThisAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VCallOffsetOffset - The offset (in bytes), relative to the address point, + /// of the virtual call offset. + int64_t VCallOffsetOffset; + + ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } + + friend bool operator==(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; + } + + friend bool operator<(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset < RHS.VCallOffsetOffset; + } +}; + +/// ThunkInfo - The 'this' pointer adjustment as well as an optional return +/// adjustment for a thunk. +struct ThunkInfo { + /// This - The 'this' pointer adjustment. + ThisAdjustment This; + + /// Return - The return adjustment. + ReturnAdjustment Return; + + ThunkInfo() { } + + ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) + : This(This), Return(Return) { } + + friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { + return LHS.This == RHS.This && LHS.Return == RHS.Return; + } + + friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) { + if (LHS.This < RHS.This) + return true; + + return LHS.This == RHS.This && LHS.Return < RHS.Return; + } + + bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } +}; + +// BaseSubobject - Uniquely identifies a direct or indirect base class. +// Stores both the base class decl and the offset from the most derived class to +// the base class. +class BaseSubobject { + /// Base - The base class declaration. + const CXXRecordDecl *Base; + + /// BaseOffset - The offset from the most derived class to the base class. + uint64_t BaseOffset; + +public: + BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset) + : Base(Base), BaseOffset(BaseOffset) { } + + /// getBase - Returns the base class declaration. + const CXXRecordDecl *getBase() const { return Base; } + + /// getBaseOffset - Returns the base class offset. + uint64_t getBaseOffset() const { return BaseOffset; } + + friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { + return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; + } +}; + +} // end namespace CodeGen +} // end namespace clang + +namespace llvm { + +template<> struct DenseMapInfo { + static clang::CodeGen::BaseSubobject getEmptyKey() { + return clang::CodeGen::BaseSubobject( + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey()); + } + + static clang::CodeGen::BaseSubobject getTombstoneKey() { + return clang::CodeGen::BaseSubobject( + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { + return + DenseMapInfo::getHashValue(Base.getBase()) ^ + DenseMapInfo::getHashValue(Base.getBaseOffset()); + } + + static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, + const clang::CodeGen::BaseSubobject &RHS) { + return LHS == RHS; + } +}; + +// It's OK to treat BaseSubobject as a POD type. +template <> struct isPodLike { + static const bool value = true; +}; + +} + +namespace clang { +namespace CodeGen { + +class CodeGenVTables { + 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 MethodVTableIndicesTy; + MethodVTableIndicesTy MethodVTableIndices; + + typedef std::pair ClassPairTy; + + /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to + /// the address point) in bytes where the offsets for virtual bases of a class + /// are stored. + typedef llvm::DenseMap + VirtualBaseClassOffsetOffsetsMapTy; + VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; + + /// VTables - All the vtables which have been defined. + llvm::DenseMap VTables; + + /// NumVirtualFunctionPointers - Contains the number of virtual function + /// pointers in the vtable for a given record decl. + llvm::DenseMap NumVirtualFunctionPointers; + + typedef llvm::SmallVector ThunkInfoVectorTy; + typedef llvm::DenseMap ThunksMapTy; + + /// Thunks - Contains all thunks that a given method decl will need. + ThunksMapTy Thunks; + + typedef llvm::DenseMap VTableLayoutMapTy; + + /// VTableLayoutMap - Stores the vtable layout for all record decls. + /// The layout is stored as an array of 64-bit integers, where the first + /// integer is the number of vtable entries in the layout, and the subsequent + /// integers are the vtable components. + VTableLayoutMapTy VTableLayoutMap; + + typedef std::pair BaseSubobjectPairTy; + typedef llvm::DenseMap AddressPointsMapTy; + + /// Address points - Address points for all vtables. + AddressPointsMapTy AddressPoints; + + /// VTableAddressPointsMapTy - Address points for a single vtable. + typedef llvm::DenseMap VTableAddressPointsMapTy; + + typedef llvm::SmallVector, 1> + VTableThunksTy; + + typedef llvm::DenseMap + VTableThunksMapTy; + + /// VTableThunksMap - Contains thunks needed by vtables. + VTableThunksMapTy VTableThunksMap; + + uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const { + assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); + + return VTableLayoutMap.lookup(RD)[0]; + } + + const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const { + assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); + + uint64_t *Components = VTableLayoutMap.lookup(RD); + return &Components[1]; + } + + typedef llvm::DenseMap SubVTTIndiciesMapTy; + + /// SubVTTIndicies - Contains indices into the various sub-VTTs. + SubVTTIndiciesMapTy SubVTTIndicies; + + typedef llvm::DenseMap + SecondaryVirtualPointerIndicesMapTy; + + /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer + /// indices. + SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; + + /// 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); + + llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *RD); + + /// EmitThunk - Emit a single thunk. + void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk); + + /// EmitThunks - Emit the associated thunks for the given global decl. + void EmitThunks(GlobalDecl GD); + + /// ComputeVTableRelatedInformation - Compute and store all vtable related + /// information (vtable layout, vbase offset offsets, thunks etc) for the + /// given record decl. + void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); + + /// CreateVTableInitializer - Create a vtable initializer for the given record + /// decl. + /// \param Components - The vtable components; this is really an array of + /// VTableComponents. + llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD, + const uint64_t *Components, + unsigned NumComponents, + const VTableThunksTy &VTableThunks); + +public: + CodeGenVTables(CodeGenModule &CGM) + : CGM(CGM) { } + + // isKeyFunctionInAnotherTU - True if this record has a key function and it is + // in another translation unit. + static bool isKeyFunctionInAnotherTU(ASTContext &Context, + const CXXRecordDecl *RD) { + assert (RD->isDynamicClass() && "Non dynamic classes have no key."); + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + return KeyFunction && !KeyFunction->getBody(); + } + + /// needsVTTParameter - Return whether the given global decl needs a VTT + /// parameter, which it does if it's a base constructor or destructor with + /// virtual bases. + static bool needsVTTParameter(GlobalDecl GD); + + /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the + /// given record decl. + uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base); + + /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the + /// virtual pointer for the given subobject is located. + uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, + BaseSubobject Base); + + /// getMethodVTableIndex - Return the index (relative to the vtable address + /// point) where the function pointer for the given virtual function is + /// stored. + uint64_t getMethodVTableIndex(GlobalDecl GD); + + /// getVirtualBaseOffsetOffset - Return the offset in bytes (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 getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); + + /// getAddressPoint - Get the address point of the given subobject in the + /// class decl. + uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); + + /// GetAddrOfVTable - Get the address of the vtable for the given record decl. + llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD); + + /// EmitVTableDefinition - Emit the definition of the given vtable. + void EmitVTableDefinition(llvm::GlobalVariable *VTable, + llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + + /// GenerateConstructionVTable - Generate a construction vtable for the given + /// base subobject. + llvm::GlobalVariable * + GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, + bool BaseIsVirtual, + VTableAddressPointsMapTy& AddressPoints); + + llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); + + // EmitVTableRelatedData - Will emit any thunks that the global decl might + // have, as well as the vtable itself if the global decl is the key function. + void EmitVTableRelatedData(GlobalDecl GD); + + /// GenerateClassData - Generate all the class data required to be generated + /// upon definition of a KeyFunction. This includes the vtable, the + /// rtti data structure and the VTT. + /// + /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. + void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); +}; + +} // end namespace CodeGen +} // end namespace clang +#endif diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 91fb714..92ef9dc 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -34,69 +34,64 @@ namespace CodeGen { /// simple LLVM SSA value, a pair of SSA values for complex numbers, or the /// address of an aggregate value in memory. class RValue { - llvm::Value *V1, *V2; - // TODO: Encode this into the low bit of pointer for more efficient - // return-by-value. - enum { Scalar, Complex, Aggregate } Flavor; + enum Flavor { Scalar, Complex, Aggregate }; - bool Volatile:1; -public: + // Stores first value and flavor. + llvm::PointerIntPair V1; + // Stores second value and volatility. + llvm::PointerIntPair V2; - bool isScalar() const { return Flavor == Scalar; } - bool isComplex() const { return Flavor == Complex; } - bool isAggregate() const { return Flavor == Aggregate; } +public: + bool isScalar() const { return V1.getInt() == Scalar; } + bool isComplex() const { return V1.getInt() == Complex; } + bool isAggregate() const { return V1.getInt() == Aggregate; } - bool isVolatileQualified() const { return Volatile; } + bool isVolatileQualified() const { return V2.getInt(); } /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); - return V1; + return V1.getPointer(); } /// getComplexVal - Return the real/imag components of this complex value. /// std::pair getComplexVal() const { - return std::pair(V1, V2); + return std::make_pair(V1.getPointer(), V2.getPointer()); } /// getAggregateAddr() - Return the Value* of the address of the aggregate. llvm::Value *getAggregateAddr() const { assert(isAggregate() && "Not an aggregate!"); - return V1; + return V1.getPointer(); } static RValue get(llvm::Value *V) { RValue ER; - ER.V1 = V; - ER.Flavor = Scalar; - ER.Volatile = false; + ER.V1.setPointer(V); + ER.V1.setInt(Scalar); + ER.V2.setInt(false); return ER; } static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { RValue ER; - ER.V1 = V1; - ER.V2 = V2; - ER.Flavor = Complex; - ER.Volatile = false; + ER.V1.setPointer(V1); + ER.V2.setPointer(V2); + ER.V1.setInt(Complex); + ER.V2.setInt(false); return ER; } static RValue getComplex(const std::pair &C) { - RValue ER; - ER.V1 = C.first; - ER.V2 = C.second; - ER.Flavor = Complex; - ER.Volatile = false; - return ER; + return getComplex(C.first, C.second); } // FIXME: Aggregate rvalues need to retain information about whether they are // volatile or not. Remove default to find all places that probably get this // wrong. - static RValue getAggregate(llvm::Value *V, bool Vol = false) { + static RValue getAggregate(llvm::Value *V, bool Volatile = false) { RValue ER; - ER.V1 = V; - ER.Flavor = Aggregate; - ER.Volatile = Vol; + ER.V1.setPointer(V); + ER.V1.setInt(Aggregate); + ER.V2.setInt(Volatile); return ER; } }; @@ -220,7 +215,7 @@ public: } // bitfield lvalue - llvm::Value *getBitFieldAddr() const { + llvm::Value *getBitFieldBaseAddr() const { assert(isBitField()); return V; } @@ -269,11 +264,17 @@ public: return R; } - static LValue MakeBitfield(llvm::Value *V, const CGBitFieldInfo &Info, + /// \brief Create a new object to represent a bit-field access. + /// + /// \param BaseValue - The base address of the structure containing the + /// bit-field. + /// \param Info - The information describing how to perform the bit-field + /// access. + static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info, unsigned CVR) { LValue R; R.LVType = BitField; - R.V = V; + R.V = BaseValue; R.BitFieldInfo = &Info; R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp deleted file mode 100644 index fc6d1a8..0000000 --- a/lib/CodeGen/CGVtable.cpp +++ /dev/null @@ -1,3170 +0,0 @@ -//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code dealing with C++ code generation of virtual tables. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenModule.h" -#include "CodeGenFunction.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/RecordLayout.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Format.h" -#include -#include - -using namespace clang; -using namespace CodeGen; - -namespace { - -/// BaseOffset - Represents an offset from a derived class to a direct or -/// indirect base class. -struct BaseOffset { - /// DerivedClass - The derived class. - const CXXRecordDecl *DerivedClass; - - /// VirtualBase - If the path from the derived class to the base class - /// involves a virtual base class, this holds its declaration. - const CXXRecordDecl *VirtualBase; - - /// NonVirtualOffset - The offset from the derived class to the base class. - /// (Or the offset from the virtual base class to the base class, if the - /// path from the derived class to the base class involves a virtual base - /// class. - int64_t NonVirtualOffset; - - BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } - BaseOffset(const CXXRecordDecl *DerivedClass, - const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) - : DerivedClass(DerivedClass), VirtualBase(VirtualBase), - NonVirtualOffset(NonVirtualOffset) { } - - bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } -}; - -/// FinalOverriders - Contains the final overrider member functions for all -/// member functions in the base subobjects of a class. -class FinalOverriders { -public: - /// OverriderInfo - Information about a final overrider. - struct OverriderInfo { - /// Method - The method decl of the overrider. - const CXXMethodDecl *Method; - - /// Offset - the base offset of the overrider in the layout class. - uint64_t Offset; - - OverriderInfo() : Method(0), Offset(0) { } - }; - -private: - /// MostDerivedClass - The most derived class for which the final overriders - /// are stored. - const CXXRecordDecl *MostDerivedClass; - - /// MostDerivedClassOffset - If we're building final overriders for a - /// construction vtable, this holds the offset from the layout class to the - /// most derived class. - const uint64_t MostDerivedClassOffset; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if the final overriders are for a - /// construction vtable. - const CXXRecordDecl *LayoutClass; - - ASTContext &Context; - - /// MostDerivedClassLayout - the AST record layout of the most derived class. - const ASTRecordLayout &MostDerivedClassLayout; - - /// BaseSubobjectMethodPairTy - Uniquely identifies a member function - /// in a base subobject. - typedef std::pair - BaseSubobjectMethodPairTy; - - typedef llvm::DenseMap OverridersMapTy; - - /// OverridersMap - The final overriders for all virtual member functions of - /// all the base subobjects of the most derived class. - OverridersMapTy OverridersMap; - - /// VisitedVirtualBases - A set of all the visited virtual bases, used to - /// avoid visiting virtual bases more than once. - llvm::SmallPtrSet VisitedVirtualBases; - - typedef llvm::DenseMap - AdjustmentOffsetsMapTy; - - /// ReturnAdjustments - Holds return adjustments for all the overriders that - /// need to perform return value adjustments. - AdjustmentOffsetsMapTy ReturnAdjustments; - - // FIXME: We might be able to get away with making this a SmallSet. - typedef llvm::SmallSetVector OffsetSetVectorTy; - - /// SubobjectOffsetsMapTy - This map is used for keeping track of all the - /// base subobject offsets that a single class declaration might refer to. - /// - /// For example, in: - /// - /// struct A { virtual void f(); }; - /// struct B1 : A { }; - /// struct B2 : A { }; - /// struct C : B1, B2 { virtual void f(); }; - /// - /// when we determine that C::f() overrides A::f(), we need to update the - /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map - /// will have the subobject offsets for both A copies. - typedef llvm::DenseMap - SubobjectOffsetsMapTy; - - /// ComputeFinalOverriders - Compute the final overriders for a given base - /// subobject (and all its direct and indirect bases). - void ComputeFinalOverriders(BaseSubobject Base, - bool BaseSubobjectIsVisitedVBase, - uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets); - - /// AddOverriders - Add the final overriders for this base subobject to the - /// map of final overriders. - void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets); - - /// PropagateOverrider - Propagate the NewMD overrider to all the functions - /// that OldMD overrides. For example, if we have: - /// - /// struct A { virtual void f(); }; - /// struct B : A { virtual void f(); }; - /// struct C : B { virtual void f(); }; - /// - /// and we want to override B::f with C::f, we also need to override A::f with - /// C::f. - void PropagateOverrider(const CXXMethodDecl *OldMD, - BaseSubobject NewBase, - uint64_t OverriderOffsetInLayoutClass, - const CXXMethodDecl *NewMD, - SubobjectOffsetsMapTy &Offsets); - - static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, - SubobjectOffsetsMapTy &Offsets); - -public: - FinalOverriders(const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, - const CXXRecordDecl *LayoutClass); - - /// getOverrider - Get the final overrider for the given method declaration in - /// the given base subobject. - OverriderInfo getOverrider(BaseSubobject Base, - const CXXMethodDecl *MD) const { - assert(OverridersMap.count(std::make_pair(Base, MD)) && - "Did not find overrider!"); - - return OverridersMap.lookup(std::make_pair(Base, MD)); - } - - /// getReturnAdjustmentOffset - Get the return adjustment offset for the - /// method decl in the given base subobject. Returns an empty base offset if - /// no adjustment is needed. - BaseOffset getReturnAdjustmentOffset(BaseSubobject Base, - const CXXMethodDecl *MD) const { - return ReturnAdjustments.lookup(std::make_pair(Base, MD)); - } - - /// dump - dump the final overriders. - void dump() { - assert(VisitedVirtualBases.empty() && - "Visited virtual bases aren't empty!"); - dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0)); - VisitedVirtualBases.clear(); - } - - /// dump - dump the final overriders for a base subobject, and all its direct - /// and indirect base subobjects. - void dump(llvm::raw_ostream &Out, BaseSubobject Base); -}; - -#define DUMP_OVERRIDERS 0 - -FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, - const CXXRecordDecl *LayoutClass) - : MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), - Context(MostDerivedClass->getASTContext()), - MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { - - // Compute the final overriders. - SubobjectOffsetsMapTy Offsets; - ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), - /*BaseSubobjectIsVisitedVBase=*/false, - MostDerivedClassOffset, Offsets); - VisitedVirtualBases.clear(); - -#if DUMP_OVERRIDERS - // And dump them (for now). - dump(); - - // Also dump the base offsets (for now). - for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(), - E = Offsets.end(); I != E; ++I) { - const OffsetSetVectorTy& OffsetSetVector = I->second; - - llvm::errs() << "Base offsets for "; - llvm::errs() << I->first->getQualifiedNameAsString() << '\n'; - - for (unsigned I = 0, E = OffsetSetVector.size(); I != E; ++I) - llvm::errs() << " " << I << " - " << OffsetSetVector[I] / 8 << '\n'; - } -#endif -} - -void FinalOverriders::AddOverriders(BaseSubobject Base, - uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets) { - const CXXRecordDecl *RD = Base.getBase(); - - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - // First, propagate the overrider. - PropagateOverrider(MD, Base, OffsetInLayoutClass, MD, Offsets); - - // Add the overrider as the final overrider of itself. - OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; - assert(!Overrider.Method && "Overrider should not exist yet!"); - - Overrider.Offset = OffsetInLayoutClass; - Overrider.Method = MD; - } -} - -static BaseOffset ComputeBaseOffset(ASTContext &Context, - const CXXRecordDecl *DerivedRD, - const CXXBasePath &Path) { - int64_t NonVirtualOffset = 0; - - unsigned NonVirtualStart = 0; - const CXXRecordDecl *VirtualBase = 0; - - // First, look for the virtual base class. - for (unsigned I = 0, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - - if (Element.Base->isVirtual()) { - // FIXME: Can we break when we find the first virtual base? - // (If we can't, can't we just iterate over the path in reverse order?) - NonVirtualStart = I + 1; - QualType VBaseType = Element.Base->getType(); - VirtualBase = - cast(VBaseType->getAs()->getDecl()); - } - } - - // Now compute the non-virtual offset. - for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - - // Check the base class offset. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - - const RecordType *BaseType = Element.Base->getType()->getAs(); - const CXXRecordDecl *Base = cast(BaseType->getDecl()); - - NonVirtualOffset += Layout.getBaseClassOffset(Base); - } - - // FIXME: This should probably use CharUnits or something. Maybe we should - // even change the base offsets in ASTRecordLayout to be specified in - // CharUnits. - return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); - -} - -static BaseOffset ComputeBaseOffset(ASTContext &Context, - const CXXRecordDecl *BaseRD, - const CXXRecordDecl *DerivedRD) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - - if (!const_cast(DerivedRD)-> - isDerivedFrom(const_cast(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return BaseOffset(); - } - - return ComputeBaseOffset(Context, DerivedRD, Paths.front()); -} - -static BaseOffset -ComputeReturnAdjustmentBaseOffset(ASTContext &Context, - const CXXMethodDecl *DerivedMD, - const CXXMethodDecl *BaseMD) { - const FunctionType *BaseFT = BaseMD->getType()->getAs(); - const FunctionType *DerivedFT = DerivedMD->getType()->getAs(); - - // Canonicalize the return types. - CanQualType CanDerivedReturnType = - Context.getCanonicalType(DerivedFT->getResultType()); - CanQualType CanBaseReturnType = - Context.getCanonicalType(BaseFT->getResultType()); - - assert(CanDerivedReturnType->getTypeClass() == - CanBaseReturnType->getTypeClass() && - "Types must have same type class!"); - - if (CanDerivedReturnType == CanBaseReturnType) { - // No adjustment needed. - return BaseOffset(); - } - - if (isa(CanDerivedReturnType)) { - CanDerivedReturnType = - CanDerivedReturnType->getAs()->getPointeeType(); - CanBaseReturnType = - CanBaseReturnType->getAs()->getPointeeType(); - } else if (isa(CanDerivedReturnType)) { - CanDerivedReturnType = - CanDerivedReturnType->getAs()->getPointeeType(); - CanBaseReturnType = - CanBaseReturnType->getAs()->getPointeeType(); - } else { - assert(false && "Unexpected return type!"); - } - - // We need to compare unqualified types here; consider - // const T *Base::foo(); - // T *Derived::foo(); - if (CanDerivedReturnType.getUnqualifiedType() == - CanBaseReturnType.getUnqualifiedType()) { - // No adjustment needed. - return BaseOffset(); - } - - const CXXRecordDecl *DerivedRD = - cast(cast(CanDerivedReturnType)->getDecl()); - - const CXXRecordDecl *BaseRD = - cast(cast(CanBaseReturnType)->getDecl()); - - return ComputeBaseOffset(Context, BaseRD, DerivedRD); -} - -void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, - BaseSubobject NewBase, - uint64_t OverriderOffsetInLayoutClass, - const CXXMethodDecl *NewMD, - SubobjectOffsetsMapTy &Offsets) { - for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(), - E = OldMD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - - // We want to override OverriddenMD in all subobjects, for example: - // - /// struct A { virtual void f(); }; - /// struct B1 : A { }; - /// struct B2 : A { }; - /// struct C : B1, B2 { virtual void f(); }; - /// - /// When overriding A::f with C::f we need to do so in both A subobjects. - const OffsetSetVectorTy &OffsetVector = Offsets[OverriddenRD]; - - // Go through all the subobjects. - for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { - uint64_t Offset = OffsetVector[I]; - - BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset); - BaseSubobjectMethodPairTy SubobjectAndMethod = - std::make_pair(OverriddenSubobject, OverriddenMD); - - OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod]; - - assert(Overrider.Method && "Did not find existing overrider!"); - - // Check if we need return adjustments or base adjustments. - // (We don't want to do this for pure virtual member functions). - if (!NewMD->isPure()) { - // Get the return adjustment base offset. - BaseOffset ReturnBaseOffset = - ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD); - - if (!ReturnBaseOffset.isEmpty()) { - // Store the return adjustment base offset. - ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; - } - } - - // Set the new overrider. - Overrider.Offset = OverriderOffsetInLayoutClass; - Overrider.Method = NewMD; - - // And propagate it further. - PropagateOverrider(OverriddenMD, NewBase, OverriderOffsetInLayoutClass, - NewMD, Offsets); - } - } -} - -void -FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, - SubobjectOffsetsMapTy &Offsets) { - // Iterate over the new offsets. - for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(), - E = NewOffsets.end(); I != E; ++I) { - const CXXRecordDecl *NewRD = I->first; - const OffsetSetVectorTy& NewOffsetVector = I->second; - - OffsetSetVectorTy &OffsetVector = Offsets[NewRD]; - - // Merge the new offsets set vector into the old. - OffsetVector.insert(NewOffsetVector.begin(), NewOffsetVector.end()); - } -} - -void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, - bool BaseSubobjectIsVisitedVBase, - uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - SubobjectOffsetsMapTy NewOffsets; - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Ignore bases that don't have any virtual member functions. - if (!BaseDecl->isPolymorphic()) - continue; - - bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase; - uint64_t BaseOffset; - uint64_t BaseOffsetInLayoutClass; - if (I->isVirtual()) { - if (!VisitedVirtualBases.insert(BaseDecl)) - IsVisitedVirtualBase = true; - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); - BaseOffsetInLayoutClass = Layout.getBaseClassOffset(BaseDecl) + - OffsetInLayoutClass; - } - - // Compute the final overriders for this base. - // We always want to compute the final overriders, even if the base is a - // visited virtual base. Consider: - // - // struct A { - // virtual void f(); - // virtual void g(); - // }; - // - // struct B : virtual A { - // void f(); - // }; - // - // struct C : virtual A { - // void g (); - // }; - // - // struct D : B, C { }; - // - // Here, we still want to compute the overriders for A as a base of C, - // because otherwise we'll miss that C::g overrides A::f. - ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), - IsVisitedVirtualBase, BaseOffsetInLayoutClass, - NewOffsets); - } - - /// Now add the overriders for this particular subobject. - /// (We don't want to do this more than once for a virtual base). - if (!BaseSubobjectIsVisitedVBase) - AddOverriders(Base, OffsetInLayoutClass, NewOffsets); - - // And merge the newly discovered subobject offsets. - MergeSubobjectOffsets(NewOffsets, Offsets); - - /// Finally, add the offset for our own subobject. - Offsets[RD].insert(Base.getBaseOffset()); -} - -void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Ignore bases that don't have any virtual member functions. - if (!BaseDecl->isPolymorphic()) - continue; - - uint64_t BaseOffset; - if (I->isVirtual()) { - if (!VisitedVirtualBases.insert(BaseDecl)) { - // We've visited this base before. - continue; - } - - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffset = Layout.getBaseClassOffset(BaseDecl) + - Base.getBaseOffset(); - } - - dump(Out, BaseSubobject(BaseDecl, BaseOffset)); - } - - Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; - Out << Base.getBaseOffset() / 8 << ")\n"; - - // Now dump the overriders for this base subobject. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - OverriderInfo Overrider = getOverrider(Base, MD); - - Out << " " << MD->getQualifiedNameAsString() << " - ("; - Out << Overrider.Method->getQualifiedNameAsString(); - Out << ", " << ", " << Overrider.Offset / 8 << ')'; - - AdjustmentOffsetsMapTy::const_iterator AI = - ReturnAdjustments.find(std::make_pair(Base, MD)); - if (AI != ReturnAdjustments.end()) { - const BaseOffset &Offset = AI->second; - - Out << " [ret-adj: "; - if (Offset.VirtualBase) - Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; - - Out << Offset.NonVirtualOffset << " nv]"; - } - - Out << "\n"; - } -} - -/// VtableComponent - Represents a single component in a vtable. -class VtableComponent { -public: - enum Kind { - CK_VCallOffset, - CK_VBaseOffset, - CK_OffsetToTop, - CK_RTTI, - CK_FunctionPointer, - - /// CK_CompleteDtorPointer - A pointer to the complete destructor. - CK_CompleteDtorPointer, - - /// CK_DeletingDtorPointer - A pointer to the deleting destructor. - CK_DeletingDtorPointer, - - /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer - /// will end up never being called. Such vtable function pointers are - /// represented as a CK_UnusedFunctionPointer. - CK_UnusedFunctionPointer - }; - - static VtableComponent MakeVCallOffset(int64_t Offset) { - return VtableComponent(CK_VCallOffset, Offset); - } - - static VtableComponent MakeVBaseOffset(int64_t Offset) { - return VtableComponent(CK_VBaseOffset, Offset); - } - - static VtableComponent MakeOffsetToTop(int64_t Offset) { - return VtableComponent(CK_OffsetToTop, Offset); - } - - static VtableComponent MakeRTTI(const CXXRecordDecl *RD) { - return VtableComponent(CK_RTTI, reinterpret_cast(RD)); - } - - static VtableComponent MakeFunction(const CXXMethodDecl *MD) { - assert(!isa(MD) && - "Don't use MakeFunction with destructors!"); - - return VtableComponent(CK_FunctionPointer, - reinterpret_cast(MD)); - } - - static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { - return VtableComponent(CK_CompleteDtorPointer, - reinterpret_cast(DD)); - } - - static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { - return VtableComponent(CK_DeletingDtorPointer, - reinterpret_cast(DD)); - } - - static VtableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { - assert(!isa(MD) && - "Don't use MakeUnusedFunction with destructors!"); - return VtableComponent(CK_UnusedFunctionPointer, - reinterpret_cast(MD)); - } - - static VtableComponent getFromOpaqueInteger(uint64_t I) { - return VtableComponent(I); - } - - /// getKind - Get the kind of this vtable component. - Kind getKind() const { - return (Kind)(Value & 0x7); - } - - int64_t getVCallOffset() const { - assert(getKind() == CK_VCallOffset && "Invalid component kind!"); - - return getOffset(); - } - - int64_t getVBaseOffset() const { - assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); - - return getOffset(); - } - - int64_t getOffsetToTop() const { - assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); - - return getOffset(); - } - - const CXXRecordDecl *getRTTIDecl() const { - assert(getKind() == CK_RTTI && "Invalid component kind!"); - - return reinterpret_cast(getPointer()); - } - - const CXXMethodDecl *getFunctionDecl() const { - assert(getKind() == CK_FunctionPointer); - - return reinterpret_cast(getPointer()); - } - - const CXXDestructorDecl *getDestructorDecl() const { - assert((getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); - - return reinterpret_cast(getPointer()); - } - - const CXXMethodDecl *getUnusedFunctionDecl() const { - assert(getKind() == CK_UnusedFunctionPointer); - - return reinterpret_cast(getPointer()); - } - -private: - VtableComponent(Kind ComponentKind, int64_t Offset) { - assert((ComponentKind == CK_VCallOffset || - ComponentKind == CK_VBaseOffset || - ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); - assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!"); - - Value = ((Offset << 3) | ComponentKind); - } - - VtableComponent(Kind ComponentKind, uintptr_t Ptr) { - assert((ComponentKind == CK_RTTI || - ComponentKind == CK_FunctionPointer || - ComponentKind == CK_CompleteDtorPointer || - ComponentKind == CK_DeletingDtorPointer || - ComponentKind == CK_UnusedFunctionPointer) && - "Invalid component kind!"); - - assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); - - Value = Ptr | ComponentKind; - } - - int64_t getOffset() const { - assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || - getKind() == CK_OffsetToTop) && "Invalid component kind!"); - - return Value >> 3; - } - - uintptr_t getPointer() const { - assert((getKind() == CK_RTTI || - getKind() == CK_FunctionPointer || - getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer || - getKind() == CK_UnusedFunctionPointer) && - "Invalid component kind!"); - - return static_cast(Value & ~7ULL); - } - - explicit VtableComponent(uint64_t Value) - : Value(Value) { } - - /// The kind is stored in the lower 3 bits of the value. For offsets, we - /// make use of the facts that classes can't be larger than 2^55 bytes, - /// so we store the offset in the lower part of the 61 bytes that remain. - /// (The reason that we're not simply using a PointerIntPair here is that we - /// need the offsets to be 64-bit, even when on a 32-bit machine). - int64_t Value; -}; - -/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. -struct VCallOffsetMap { - - typedef std::pair MethodAndOffsetPairTy; - - /// Offsets - Keeps track of methods and their offsets. - // FIXME: This should be a real map and not a vector. - llvm::SmallVector Offsets; - - /// MethodsCanShareVCallOffset - Returns whether two virtual member functions - /// can share the same vcall offset. - static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS); - -public: - /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the - /// add was successful, or false if there was already a member function with - /// the same signature in the map. - bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset); - - /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the - /// vtable address point) for the given virtual member function. - int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); - - // empty - Return whether the offset map is empty or not. - bool empty() const { return Offsets.empty(); } -}; - -static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS) { - ASTContext &C = LHS->getASTContext(); // TODO: thread this down - CanQual - LT = C.getCanonicalType(LHS->getType()).getAs(), - RT = C.getCanonicalType(RHS->getType()).getAs(); - - // Fast-path matches in the canonical types. - if (LT == RT) return true; - - // Force the signatures to match. We can't rely on the overrides - // list here because there isn't necessarily an inheritance - // relationship between the two methods. - if (LT.getQualifiers() != RT.getQualifiers() || - LT->getNumArgs() != RT->getNumArgs()) - return false; - for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) - if (LT->getArgType(I) != RT->getArgType(I)) - return false; - return true; -} - -bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS) { - assert(LHS->isVirtual() && "LHS must be virtual!"); - assert(RHS->isVirtual() && "LHS must be virtual!"); - - // A destructor can share a vcall offset with another destructor. - if (isa(LHS)) - return isa(RHS); - - // FIXME: We need to check more things here. - - // The methods must have the same name. - DeclarationName LHSName = LHS->getDeclName(); - DeclarationName RHSName = RHS->getDeclName(); - if (LHSName != RHSName) - return false; - - // And the same signatures. - return HasSameVirtualSignature(LHS, RHS); -} - -bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, - int64_t OffsetOffset) { - // Check if we can reuse an offset. - for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { - if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) - return false; - } - - // Add the offset. - Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); - return true; -} - -int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { - // Look for an offset. - for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { - if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) - return Offsets[I].second; - } - - assert(false && "Should always find a vcall offset offset!"); - return 0; -} - -/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. -class VCallAndVBaseOffsetBuilder { -public: - typedef llvm::DenseMap - VBaseOffsetOffsetsMapTy; - -private: - /// MostDerivedClass - The most derived class for which we're building vcall - /// and vbase offsets. - const CXXRecordDecl *MostDerivedClass; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if we're building a construction - /// vtable. - const CXXRecordDecl *LayoutClass; - - /// Context - The ASTContext which we will use for layout information. - ASTContext &Context; - - /// Components - vcall and vbase offset components - typedef llvm::SmallVector VtableComponentVectorTy; - VtableComponentVectorTy Components; - - /// VisitedVirtualBases - Visited virtual bases. - llvm::SmallPtrSet VisitedVirtualBases; - - /// VCallOffsets - Keeps track of vcall offsets. - VCallOffsetMap VCallOffsets; - - - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, - /// relative to the address point. - VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - - /// FinalOverriders - The final overriders of the most derived class. - /// (Can be null when we're not building a vtable of the most derived class). - const FinalOverriders *Overriders; - - /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the - /// given base subobject. - void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, - uint64_t RealBaseOffset); - - /// AddVCallOffsets - Add vcall offsets for the given base subobject. - void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); - - /// AddVBaseOffsets - Add vbase offsets for the given class. - void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); - - /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in - /// bytes, relative to the vtable address point. - int64_t getCurrentOffsetOffset() const; - -public: - VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, - const CXXRecordDecl *LayoutClass, - const FinalOverriders *Overriders, - BaseSubobject Base, bool BaseIsVirtual, - uint64_t OffsetInLayoutClass) - : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), - Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { - - // Add vcall and vbase offsets. - AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); - } - - /// Methods for iterating over the components. - typedef VtableComponentVectorTy::const_reverse_iterator const_iterator; - const_iterator components_begin() const { return Components.rbegin(); } - const_iterator components_end() const { return Components.rend(); } - - const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } - const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { - return VBaseOffsetOffsets; - } -}; - -void -VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t RealBaseOffset) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); - - // Itanium C++ ABI 2.5.2: - // ..in classes sharing a virtual table with a primary base class, the vcall - // and vbase offsets added by the derived class all come before the vcall - // and vbase offsets required by the base class, so that the latter may be - // laid out as required by the base class without regard to additions from - // the derived class(es). - - // (Since we're emitting the vcall and vbase offsets in reverse order, we'll - // emit them for the primary base first). - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); - - uint64_t PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (PrimaryBaseIsVirtual) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseIsVirtual, RealBaseOffset); - } - - AddVBaseOffsets(Base.getBase(), RealBaseOffset); - - // We only want to add vcall offsets for virtual bases. - if (BaseIsVirtual) - AddVCallOffsets(Base, RealBaseOffset); -} - -int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { - // OffsetIndex is the index of this vcall or vbase offset, relative to the - // vtable address point. (We subtract 3 to account for the information just - // above the address point, the RTTI info, the offset to top, and the - // vcall offset itself). - int64_t OffsetIndex = -(int64_t)(3 + Components.size()); - - // FIXME: We shouldn't use / 8 here. - int64_t OffsetOffset = OffsetIndex * - (int64_t)Context.Target.getPointerWidth(0) / 8; - - return OffsetOffset; -} - -void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, - uint64_t VBaseOffset) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - // Handle the primary base first. - if (PrimaryBase) { - uint64_t PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - VBaseOffset); - } - - // Add the vcall offsets. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - int64_t OffsetOffset = getCurrentOffsetOffset(); - - // Don't add a vcall offset if we already have one for this member function - // signature. - if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) - continue; - - int64_t Offset = 0; - - if (Overriders) { - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders->getOverrider(Base, MD); - - /// The vcall offset is the offset from the virtual base to the object - /// where the function was overridden. - // FIXME: We should not use / 8 here. - Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; - } - - Components.push_back(VtableComponent::MakeVCallOffset(Offset)); - } - - // And iterate over all non-virtual bases (ignoring the primary base). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - if (BaseDecl == PrimaryBase) - continue; - - // Get the base offset of this base. - uint64_t BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - - AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); - } -} - -void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass) { - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - // Add vbase offsets. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Check if this is a virtual base that we haven't visited before. - if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { - // FIXME: We shouldn't use / 8 here. - int64_t Offset = - (int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) - - OffsetInLayoutClass) / 8; - - // Add the vbase offset offset. - assert(!VBaseOffsetOffsets.count(BaseDecl) && - "vbase offset offset already exists!"); - - int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); - VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); - - Components.push_back(VtableComponent::MakeVBaseOffset(Offset)); - } - - // Check the base class looking for more vbase offsets. - AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); - } -} - -/// VtableBuilder - Class for building vtable layout information. -class VtableBuilder { -public: - /// PrimaryBasesSetVectorTy - A set vector of direct and indirect - /// primary bases. - typedef llvm::SmallSetVector - PrimaryBasesSetVectorTy; - - typedef llvm::DenseMap - VBaseOffsetOffsetsMapTy; - - typedef llvm::DenseMap - AddressPointsMapTy; - -private: - /// VTables - Global vtable information. - CodeGenVTables &VTables; - - /// MostDerivedClass - The most derived class for which we're building this - /// vtable. - const CXXRecordDecl *MostDerivedClass; - - /// MostDerivedClassOffset - If we're building a construction vtable, this - /// holds the offset from the layout class to the most derived class. - const uint64_t MostDerivedClassOffset; - - /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual - /// base. (This only makes sense when building a construction vtable). - bool MostDerivedClassIsVirtual; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if we're building a construction - /// vtable. - const CXXRecordDecl *LayoutClass; - - /// Context - The ASTContext which we will use for layout information. - ASTContext &Context; - - /// FinalOverriders - The final overriders of the most derived class. - const FinalOverriders Overriders; - - /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual - /// bases in this vtable. - llvm::DenseMap VCallOffsetsForVBases; - - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for - /// the most derived class. - VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - - /// Components - The components of the vtable being built. - llvm::SmallVector Components; - - /// AddressPoints - Address points for the vtable being built. - AddressPointsMapTy AddressPoints; - - /// MethodInfo - Contains information about a method in a vtable. - /// (Used for computing 'this' pointer adjustment thunks. - struct MethodInfo { - /// BaseOffset - The base offset of this method. - const uint64_t BaseOffset; - - /// BaseOffsetInLayoutClass - The base offset in the layout class of this - /// method. - const uint64_t BaseOffsetInLayoutClass; - - /// VtableIndex - The index in the vtable that this method has. - /// (For destructors, this is the index of the complete destructor). - const uint64_t VtableIndex; - - MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, - uint64_t VtableIndex) - : BaseOffset(BaseOffset), - BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), - VtableIndex(VtableIndex) { } - - MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { } - }; - - typedef llvm::DenseMap MethodInfoMapTy; - - /// MethodInfoMap - The information for all methods in the vtable we're - /// currently building. - MethodInfoMapTy MethodInfoMap; - - typedef llvm::DenseMap VtableThunksMapTy; - - /// VTableThunks - The thunks by vtable index in the vtable currently being - /// built. - VtableThunksMapTy VTableThunks; - - typedef llvm::SmallVector ThunkInfoVectorTy; - typedef llvm::DenseMap ThunksMapTy; - - /// Thunks - A map that contains all the thunks needed for all methods in the - /// most derived class for which the vtable is currently being built. - ThunksMapTy Thunks; - - /// AddThunk - Add a thunk for the given method. - void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk); - - /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the - /// part of the vtable we're currently building. - void ComputeThisAdjustments(); - - typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; - - /// PrimaryVirtualBases - All known virtual bases who are a primary base of - /// some other base. - VisitedVirtualBasesSetTy PrimaryVirtualBases; - - /// ComputeReturnAdjustment - Compute the return adjustment given a return - /// adjustment base offset. - ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); - - /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting - /// the 'this' pointer from the base subobject to the derived subobject. - BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const; - - /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the - /// given virtual member function, its offset in the layout class and its - /// final overrider. - ThisAdjustment - ComputeThisAdjustment(const CXXMethodDecl *MD, - uint64_t BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider); - - /// AddMethod - Add a single virtual member function to the vtable - /// components vector. - void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); - - /// IsOverriderUsed - Returns whether the overrider will ever be used in this - /// part of the vtable. - /// - /// Itanium C++ ABI 2.5.2: - /// - /// struct A { virtual void f(); }; - /// struct B : virtual public A { int i; }; - /// struct C : virtual public A { int j; }; - /// struct D : public B, public C {}; - /// - /// When B and C are declared, A is a primary base in each case, so although - /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this - /// adjustment is required and no thunk is generated. However, inside D - /// objects, A is no longer a primary base of C, so if we allowed calls to - /// C::f() to use the copy of A's vtable in the C subobject, we would need - /// to adjust this from C* to B::A*, which would require a third-party - /// thunk. Since we require that a call to C::f() first convert to A*, - /// C-in-D's copy of A's vtable is never referenced, so this is not - /// necessary. - bool IsOverriderUsed(const CXXMethodDecl *Overrider, - uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass) const; - - - /// AddMethods - Add the methods of this base subobject and all its - /// primary bases to the vtable components vector. - void AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases); - - // LayoutVtable - Layout the vtable for the given base class, including its - // secondary vtables and any vtables for virtual bases. - void LayoutVtable(); - - /// LayoutPrimaryAndSecondaryVtables - Layout the primary vtable for the - /// given base subobject, as well as all its secondary vtables. - void LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t OffsetInLayoutClass); - - /// LayoutSecondaryVtables - Layout the secondary vtables for the given base - /// subobject. - /// - /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual, - uint64_t OffsetInLayoutClass); - - /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this - /// class hierarchy. - void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases); - - /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the - /// given base (excluding any primary bases). - void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases); - - /// isBuildingConstructionVtable - Return whether this vtable builder is - /// building a construction vtable. - bool isBuildingConstructorVtable() const { - return MostDerivedClass != LayoutClass; - } - -public: - VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, - const CXXRecordDecl *LayoutClass) - : VTables(VTables), MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), - MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), - LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), - Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { - - LayoutVtable(); - } - - ThunksMapTy::const_iterator thunks_begin() const { - return Thunks.begin(); - } - - ThunksMapTy::const_iterator thunks_end() const { - return Thunks.end(); - } - - const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { - return VBaseOffsetOffsets; - } - - /// getNumVTableComponents - Return the number of components in the vtable - /// currently built. - uint64_t getNumVTableComponents() const { - return Components.size(); - } - - const uint64_t *vtable_components_data_begin() const { - return reinterpret_cast(Components.begin()); - } - - const uint64_t *vtable_components_data_end() const { - return reinterpret_cast(Components.end()); - } - - AddressPointsMapTy::const_iterator address_points_begin() const { - return AddressPoints.begin(); - } - - AddressPointsMapTy::const_iterator address_points_end() const { - return AddressPoints.end(); - } - - VtableThunksMapTy::const_iterator vtable_thunks_begin() const { - return VTableThunks.begin(); - } - - VtableThunksMapTy::const_iterator vtable_thunks_end() const { - return VTableThunks.end(); - } - - /// dumpLayout - Dump the vtable layout. - void dumpLayout(llvm::raw_ostream&); -}; - -void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { - assert(!isBuildingConstructorVtable() && - "Can't add thunks for construction vtable"); - - llvm::SmallVector &ThunksVector = Thunks[MD]; - - // Check if we have this thunk already. - if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != - ThunksVector.end()) - return; - - ThunksVector.push_back(Thunk); -} - -/// OverridesMethodInBases - Checks whether whether this virtual member -/// function overrides a member function in any of the given bases. -/// Returns the overridden member function, or null if none was found. -static const CXXMethodDecl * -OverridesMethodInBases(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { - 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 (Bases.count(OverriddenRD)) - return OverriddenMD; - } - - return 0; -} - -void VtableBuilder::ComputeThisAdjustments() { - // Now go through the method info map and see if any of the methods need - // 'this' pointer adjustments. - for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), - E = MethodInfoMap.end(); I != E; ++I) { - const CXXMethodDecl *MD = I->first; - const MethodInfo &MethodInfo = I->second; - - // Ignore adjustments for unused function pointers. - uint64_t VtableIndex = MethodInfo.VtableIndex; - if (Components[VtableIndex].getKind() == - VtableComponent::CK_UnusedFunctionPointer) - continue; - - // Get the final overrider for this method. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(BaseSubobject(MD->getParent(), - MethodInfo.BaseOffset), MD); - - // Check if we need an adjustment at all. - if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) { - // When a return thunk is needed by a derived class that overrides a - // virtual base, gcc uses a virtual 'this' adjustment as well. - // While the thunk itself might be needed by vtables in subclasses or - // in construction vtables, there doesn't seem to be a reason for using - // the thunk in this vtable. Still, we do so to match gcc. - if (VTableThunks.lookup(VtableIndex).Return.isEmpty()) - continue; - } - - ThisAdjustment ThisAdjustment = - ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); - - if (ThisAdjustment.isEmpty()) - continue; - - // Add it. - VTableThunks[VtableIndex].This = ThisAdjustment; - - if (isa(MD)) { - // Add an adjustment for the deleting destructor as well. - VTableThunks[VtableIndex + 1].This = ThisAdjustment; - } - } - - /// Clear the method info map. - MethodInfoMap.clear(); - - if (isBuildingConstructorVtable()) { - // We don't need to store thunk information for construction vtables. - return; - } - - for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(), - E = VTableThunks.end(); I != E; ++I) { - const VtableComponent &Component = Components[I->first]; - const ThunkInfo &Thunk = I->second; - const CXXMethodDecl *MD; - - switch (Component.getKind()) { - default: - llvm_unreachable("Unexpected vtable component kind!"); - case VtableComponent::CK_FunctionPointer: - MD = Component.getFunctionDecl(); - break; - case VtableComponent::CK_CompleteDtorPointer: - MD = Component.getDestructorDecl(); - break; - case VtableComponent::CK_DeletingDtorPointer: - // We've already added the thunk when we saw the complete dtor pointer. - continue; - } - - if (MD->getParent() == MostDerivedClass) - AddThunk(MD, Thunk); - } -} - -ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { - ReturnAdjustment Adjustment; - - if (!Offset.isEmpty()) { - if (Offset.VirtualBase) { - // Get the virtual base offset offset. - if (Offset.DerivedClass == MostDerivedClass) { - // We can get the offset offset directly from our map. - Adjustment.VBaseOffsetOffset = - VBaseOffsetOffsets.lookup(Offset.VirtualBase); - } else { - Adjustment.VBaseOffsetOffset = - VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, - Offset.VirtualBase); - } - - // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again, - // we can get rid of this assert. - assert(Adjustment.VBaseOffsetOffset != 0 && - "Invalid vbase offset offset!"); - } - - Adjustment.NonVirtual = Offset.NonVirtualOffset; - } - - return Adjustment; -} - -BaseOffset -VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const { - const CXXRecordDecl *BaseRD = Base.getBase(); - const CXXRecordDecl *DerivedRD = Derived.getBase(); - - CXXBasePaths Paths(/*FindAmbiguities=*/true, - /*RecordPaths=*/true, /*DetectVirtual=*/true); - - if (!const_cast(DerivedRD)-> - isDerivedFrom(const_cast(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return BaseOffset(); - } - - // We have to go through all the paths, and see which one leads us to the - // right base subobject. - for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); - I != E; ++I) { - BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); - - // FIXME: Should not use * 8 here. - uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8; - - if (Offset.VirtualBase) { - // If we have a virtual base class, the non-virtual offset is relative - // to the virtual base class offset. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - /// Get the virtual base offset, relative to the most derived class - /// layout. - OffsetToBaseSubobject += - LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); - } else { - // Otherwise, the non-virtual offset is relative to the derived class - // offset. - OffsetToBaseSubobject += Derived.getBaseOffset(); - } - - // Check if this path gives us the right base subobject. - if (OffsetToBaseSubobject == Base.getBaseOffset()) { - // Since we're going from the base class _to_ the derived class, we'll - // invert the non-virtual offset here. - Offset.NonVirtualOffset = -Offset.NonVirtualOffset; - return Offset; - } - } - - return BaseOffset(); -} - -ThisAdjustment -VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - uint64_t BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider) { - // Ignore adjustments for pure virtual member functions. - if (Overrider.Method->isPure()) - return ThisAdjustment(); - - BaseSubobject OverriddenBaseSubobject(MD->getParent(), - BaseOffsetInLayoutClass); - - BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), - Overrider.Offset); - - // Compute the adjustment offset. - BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, - OverriderBaseSubobject); - if (Offset.isEmpty()) - return ThisAdjustment(); - - ThisAdjustment Adjustment; - - if (Offset.VirtualBase) { - // Get the vcall offset map for this virtual base. - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; - - if (VCallOffsets.empty()) { - // We don't have vcall offsets for this virtual base, go ahead and - // build them. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, - /*FinalOverriders=*/0, - BaseSubobject(Offset.VirtualBase, 0), - /*BaseIsVirtual=*/true, - /*OffsetInLayoutClass=*/0); - - VCallOffsets = Builder.getVCallOffsets(); - } - - Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); - } - - // Set the non-virtual part of the adjustment. - Adjustment.NonVirtual = Offset.NonVirtualOffset; - - return Adjustment; -} - -void -VtableBuilder::AddMethod(const CXXMethodDecl *MD, - ReturnAdjustment ReturnAdjustment) { - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - assert(ReturnAdjustment.isEmpty() && - "Destructor can't have return adjustment!"); - - // Add both the complete destructor and the deleting destructor. - Components.push_back(VtableComponent::MakeCompleteDtor(DD)); - Components.push_back(VtableComponent::MakeDeletingDtor(DD)); - } else { - // Add the return adjustment if necessary. - if (!ReturnAdjustment.isEmpty()) - VTableThunks[Components.size()].Return = ReturnAdjustment; - - // Add the function. - Components.push_back(VtableComponent::MakeFunction(MD)); - } -} - -/// OverridesIndirectMethodInBase - Return whether the given member function -/// overrides any methods in the set of given bases. -/// Unlike OverridesMethodInBase, this checks "overriders of overriders". -/// For example, if we have: -/// -/// struct A { virtual void f(); } -/// struct B : A { virtual void f(); } -/// struct C : B { virtual void f(); } -/// -/// OverridesIndirectMethodInBase will return true if given C::f as the method -/// and { A } as the set of bases. -static bool -OverridesIndirectMethodInBases(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { - 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 (Bases.count(OverriddenRD)) - return true; - - // Check "indirect overriders". - if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) - return true; - } - - return false; -} - -bool -VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, - uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass) const { - // If the base and the first base in the primary base chain have the same - // offsets, then this overrider will be used. - if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) - return true; - - // We know now that Base (or a direct or indirect base of it) is a primary - // base in part of the class hierarchy, but not a primary base in the most - // derived class. - - // If the overrider is the first base in the primary base chain, we know - // that the overrider will be used. - if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) - return true; - - VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - - const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; - PrimaryBases.insert(RD); - - // Now traverse the base chain, starting with the first base, until we find - // the base that is no longer a primary base. - while (true) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - break; - - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary base should always be at offset 0!"); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - // Now check if this is the primary base that is not a primary base in the - // most derived class. - if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != - FirstBaseOffsetInLayoutClass) { - // We found it, stop walking the chain. - break; - } - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should always be at offset 0!"); - } - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); - - RD = PrimaryBase; - } - - // If the final overrider is an override of one of the primary bases, - // then we know that it will be used. - return OverridesIndirectMethodInBases(Overrider, PrimaryBases); -} - -/// FindNearestOverriddenMethod - Given a method, returns the overridden method -/// from the nearest base. Returns null if no method was found. -static const CXXMethodDecl * -FindNearestOverriddenMethod(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { - for (int I = Bases.size(), E = 0; I != E; --I) { - const CXXRecordDecl *PrimaryBase = Bases[I - 1]; - - // Now check the overriden methods. - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - - // We found our overridden method. - if (OverriddenMD->getParent() == PrimaryBase) - return OverriddenMD; - } - } - - return 0; -} - -void -VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - uint64_t PrimaryBaseOffset; - uint64_t PrimaryBaseOffsetInLayoutClass; - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; - } - - AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, - FirstBaseOffsetInLayoutClass, PrimaryBases); - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); - } - - // Now go through all virtual member functions and add them. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(Base, MD); - - // Check if this virtual member function overrides a method in a primary - // base. If this is the case, and the return type doesn't require adjustment - // then we can just use the member function from the primary base. - if (const CXXMethodDecl *OverriddenMD = - FindNearestOverriddenMethod(MD, PrimaryBases)) { - if (ComputeReturnAdjustmentBaseOffset(Context, MD, - OverriddenMD).isEmpty()) { - // Replace the method info of the overridden method with our own - // method. - assert(MethodInfoMap.count(OverriddenMD) && - "Did not find the overridden method!"); - MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; - - MethodInfo MethodInfo(Base.getBaseOffset(), - BaseOffsetInLayoutClass, - OverriddenMethodInfo.VtableIndex); - - assert(!MethodInfoMap.count(MD) && - "Should not have method info for this method yet!"); - - MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); - MethodInfoMap.erase(OverriddenMD); - - // If the overridden method exists in a virtual base class or a direct - // or indirect base class of a virtual base class, we need to emit a - // thunk if we ever have a class hierarchy where the base class is not - // a primary base in the complete object. - if (!isBuildingConstructorVtable() && OverriddenMD != MD) { - // Compute the this adjustment. - ThisAdjustment ThisAdjustment = - ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, - Overrider); - - if (ThisAdjustment.VCallOffsetOffset && - Overrider.Method->getParent() == MostDerivedClass) { - // This is a virtual thunk for the most derived class, add it. - AddThunk(Overrider.Method, - ThunkInfo(ThisAdjustment, ReturnAdjustment())); - } - } - - continue; - } - } - - // Insert the method info for this method. - MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, - Components.size()); - - assert(!MethodInfoMap.count(MD) && - "Should not have method info for this method yet!"); - MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); - - // Check if this overrider is going to be used. - const CXXMethodDecl *OverriderMD = Overrider.Method; - if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, - FirstBaseInPrimaryBaseChain, - FirstBaseOffsetInLayoutClass)) { - Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD)); - continue; - } - - // Check if this overrider needs a return adjustment. - BaseOffset ReturnAdjustmentOffset = - Overriders.getReturnAdjustmentOffset(Base, MD); - - ReturnAdjustment ReturnAdjustment = - ComputeReturnAdjustment(ReturnAdjustmentOffset); - - AddMethod(Overrider.Method, ReturnAdjustment); - } -} - -void VtableBuilder::LayoutVtable() { - LayoutPrimaryAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0), - MostDerivedClassIsVirtual, - MostDerivedClassOffset); - - VisitedVirtualBasesSetTy VBases; - - // Determine the primary virtual bases. - DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, - VBases); - VBases.clear(); - - LayoutVtablesForVirtualBases(MostDerivedClass, VBases); -} - -void -VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t OffsetInLayoutClass) { - assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); - - // Add vcall and vbase offsets for this vtable. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, - Base, BaseIsVirtual, OffsetInLayoutClass); - Components.append(Builder.components_begin(), Builder.components_end()); - - // Check if we need to add these vcall offsets. - if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) { - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; - - if (VCallOffsets.empty()) - VCallOffsets = Builder.getVCallOffsets(); - } - - // If we're laying out the most derived class we want to keep track of the - // virtual base class offset offsets. - if (Base.getBase() == MostDerivedClass) - VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); - - // Add the offset to top. - // FIXME: We should not use / 8 here. - int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - - MostDerivedClassOffset) / 8; - Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop)); - - // Next, add the RTTI. - Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass)); - - uint64_t AddressPoint = Components.size(); - - // Now go through all virtual member functions and add them. - PrimaryBasesSetVectorTy PrimaryBases; - AddMethods(Base, OffsetInLayoutClass, Base.getBase(), OffsetInLayoutClass, - PrimaryBases); - - // Compute 'this' pointer adjustments. - ComputeThisAdjustments(); - - // Add all address points. - const CXXRecordDecl *RD = Base.getBase(); - while (true) { - AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass), - AddressPoint)); - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - break; - - if (Layout.getPrimaryBaseWasVirtual()) { - // Check if this virtual primary base is a primary base in the layout - // class. If it's not, we don't want to add it. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != - OffsetInLayoutClass) { - // We don't want to add this class (or any of its primary bases). - break; - } - } - - RD = PrimaryBase; - } - - bool BaseIsMorallyVirtual = BaseIsVirtual; - if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass) - BaseIsMorallyVirtual = false; - - // Layout secondary vtables. - LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); -} - -void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - uint64_t OffsetInLayoutClass) { - // Itanium C++ ABI 2.5.2: - // Following the primary virtual table of a derived class are secondary - // virtual tables for each of its proper base classes, except any primary - // base(s) with which it shares its primary virtual table. - - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - // Ignore virtual bases, we'll emit them later. - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Ignore bases that don't have a vtable. - if (!BaseDecl->isDynamicClass()) - continue; - - if (isBuildingConstructorVtable()) { - // Itanium C++ ABI 2.6.4: - // Some of the base class subobjects may not need construction virtual - // tables, which will therefore not be present in the construction - // virtual table group, even though the subobject virtual tables are - // present in the main virtual table group for the complete object. - if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) - continue; - } - - // Get the base offset of this base. - uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); - uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; - - uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset; - - // Don't emit a secondary vtable for a primary base. We might however want - // to emit secondary vtables for other bases of this base. - if (BaseDecl == PrimaryBase) { - LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - BaseIsMorallyVirtual, BaseOffsetInLayoutClass); - continue; - } - - // Layout the primary vtable (and any secondary vtables) for this base. - LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsVirtual=*/false, - BaseOffsetInLayoutClass); - } -} - -void -VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Check if this base has a primary base. - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - - // Check if it's virtual. - if (Layout.getPrimaryBaseWasVirtual()) { - bool IsPrimaryVirtualBase = true; - - if (isBuildingConstructorVtable()) { - // Check if the base is actually a primary base in the class we use for - // layout. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - uint64_t PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(PrimaryBase); - - // We know that the base is not a primary base in the layout class if - // the base offsets are different. - if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) - IsPrimaryVirtualBase = false; - } - - if (IsPrimaryVirtualBase) - PrimaryVirtualBases.insert(PrimaryBase); - } - } - - // Traverse bases, looking for more primary virtual bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - uint64_t BaseOffsetInLayoutClass; - - if (I->isVirtual()) { - if (!VBases.insert(BaseDecl)) - continue; - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - BaseOffsetInLayoutClass = LayoutClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffsetInLayoutClass = - OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); - } - - DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); - } -} - -void -VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases) { - // Itanium C++ ABI 2.5.2: - // Then come the virtual base virtual tables, also in inheritance graph - // order, and again excluding primary bases (which share virtual tables with - // the classes for which they are primary). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Check if this base needs a vtable. (If it's virtual, not a primary base - // of some other class, and we haven't visited it before). - if (I->isVirtual() && BaseDecl->isDynamicClass() && - !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - uint64_t BaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - uint64_t BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - - LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsVirtual=*/true, - BaseOffsetInLayoutClass); - } - - // We only need to check the base for virtual base vtables if it actually - // has virtual bases. - if (BaseDecl->getNumVBases()) - LayoutVtablesForVirtualBases(BaseDecl, VBases); - } -} - -/// dumpLayout - Dump the vtable layout. -void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { - - if (isBuildingConstructorVtable()) { - Out << "Construction vtable for ('"; - Out << MostDerivedClass->getQualifiedNameAsString() << "', "; - // FIXME: Don't use / 8 . - Out << MostDerivedClassOffset / 8 << ") in '"; - Out << LayoutClass->getQualifiedNameAsString(); - } else { - Out << "Vtable for '"; - Out << MostDerivedClass->getQualifiedNameAsString(); - } - Out << "' (" << Components.size() << " entries).\n"; - - // Iterate through the address points and insert them into a new map where - // they are keyed by the index and not the base object. - // Since an address point can be shared by multiple subobjects, we use an - // STL multimap. - std::multimap AddressPointsByIndex; - for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), - E = AddressPoints.end(); I != E; ++I) { - const BaseSubobject& Base = I->first; - uint64_t Index = I->second; - - AddressPointsByIndex.insert(std::make_pair(Index, Base)); - } - - for (unsigned I = 0, E = Components.size(); I != E; ++I) { - uint64_t Index = I; - - Out << llvm::format("%4d | ", I); - - const VtableComponent &Component = Components[I]; - - // Dump the component. - switch (Component.getKind()) { - - case VtableComponent::CK_VCallOffset: - Out << "vcall_offset (" << Component.getVCallOffset() << ")"; - break; - - case VtableComponent::CK_VBaseOffset: - Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; - break; - - case VtableComponent::CK_OffsetToTop: - Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; - break; - - case VtableComponent::CK_RTTI: - Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; - break; - - case VtableComponent::CK_FunctionPointer: { - const CXXMethodDecl *MD = Component.getFunctionDecl(); - - std::string Str = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - Out << Str; - if (MD->isPure()) - Out << " [pure]"; - - ThunkInfo Thunk = VTableThunks.lookup(I); - if (!Thunk.isEmpty()) { - // If this function pointer has a return adjustment, dump it. - if (!Thunk.Return.isEmpty()) { - Out << "\n [return adjustment: "; - Out << Thunk.Return.NonVirtual << " non-virtual"; - - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; - Out << " vbase offset offset"; - } - - Out << ']'; - } - - // If this function pointer has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "\n [this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - - Out << ']'; - } - } - - break; - } - - case VtableComponent::CK_CompleteDtorPointer: - case VtableComponent::CK_DeletingDtorPointer: { - bool IsComplete = - Component.getKind() == VtableComponent::CK_CompleteDtorPointer; - - const CXXDestructorDecl *DD = Component.getDestructorDecl(); - - Out << DD->getQualifiedNameAsString(); - if (IsComplete) - Out << "() [complete]"; - else - Out << "() [deleting]"; - - if (DD->isPure()) - Out << " [pure]"; - - ThunkInfo Thunk = VTableThunks.lookup(I); - if (!Thunk.isEmpty()) { - // If this destructor has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "\n [this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - - Out << ']'; - } - } - - break; - } - - case VtableComponent::CK_UnusedFunctionPointer: { - const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); - - std::string Str = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - Out << "[unused] " << Str; - if (MD->isPure()) - Out << " [pure]"; - } - - } - - Out << '\n'; - - // Dump the next address point. - uint64_t NextIndex = Index + 1; - if (AddressPointsByIndex.count(NextIndex)) { - if (AddressPointsByIndex.count(NextIndex) == 1) { - const BaseSubobject &Base = - AddressPointsByIndex.find(NextIndex)->second; - - // FIXME: Instead of dividing by 8, we should be using CharUnits. - Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); - Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; - } else { - uint64_t BaseOffset = - AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); - - // We store the class names in a set to get a stable order. - std::set ClassNames; - for (std::multimap::const_iterator I = - AddressPointsByIndex.lower_bound(NextIndex), E = - AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { - assert(I->second.getBaseOffset() == BaseOffset && - "Invalid base offset!"); - const CXXRecordDecl *RD = I->second.getBase(); - ClassNames.insert(RD->getQualifiedNameAsString()); - } - - for (std::set::const_iterator I = ClassNames.begin(), - E = ClassNames.end(); I != E; ++I) { - // FIXME: Instead of dividing by 8, we should be using CharUnits. - Out << " -- (" << *I; - Out << ", " << BaseOffset / 8 << ") vtable address --\n"; - } - } - } - } - - Out << '\n'; - - if (isBuildingConstructorVtable()) - return; - - if (MostDerivedClass->getNumVBases()) { - // We store the virtual base class names and their offsets in a map to get - // a stable order. - - std::map ClassNamesAndOffsets; - for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), - E = VBaseOffsetOffsets.end(); I != E; ++I) { - std::string ClassName = I->first->getQualifiedNameAsString(); - int64_t OffsetOffset = I->second; - ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); - } - - Out << "Virtual base offset offsets for '"; - Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; - Out << ClassNamesAndOffsets.size(); - Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; - - for (std::map::const_iterator I = - ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); - I != E; ++I) - Out << " " << I->first << " | " << I->second << '\n'; - - Out << "\n"; - } - - if (!Thunks.empty()) { - // We store the method names in a map to get a stable order. - std::map MethodNamesAndDecls; - - for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end(); - I != E; ++I) { - const CXXMethodDecl *MD = I->first; - std::string MethodName = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - - MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); - } - - for (std::map::const_iterator I = - MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); - I != E; ++I) { - const std::string &MethodName = I->first; - const CXXMethodDecl *MD = I->second; - - ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end()); - - Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); - Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; - - for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { - const ThunkInfo &Thunk = ThunksVector[I]; - - Out << llvm::format("%4d | ", I); - - // If this function pointer has a return pointer adjustment, dump it. - if (!Thunk.Return.isEmpty()) { - Out << "return adjustment: " << Thunk.This.NonVirtual; - Out << " non-virtual"; - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; - Out << " vbase offset offset"; - } - - if (!Thunk.This.isEmpty()) - Out << "\n "; - } - - // If this function pointer has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - } - - Out << '\n'; - } - - Out << '\n'; - - } - } -} - -} - -void CodeGenVTables::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!"); - - // 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); - } - - // Collect all the primary bases, so we can check whether methods override - // a method from the base. - VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - for (ASTRecordLayout::primary_base_info_iterator - I = Layout.primary_base_begin(), E = Layout.primary_base_end(); - I != E; ++I) - PrimaryBases.insert((*I).getBase()); - - 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; - - // Check if this method overrides a method in the primary base. - if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInBases(MD, PrimaryBases)) { - // Check if converting from the return type of the method to the - // return type of the overridden method requires conversion. - if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, - OverriddenMD).isEmpty()) { - // This index is shared between the index in the vtable of the primary - // base class. - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - const CXXDestructorDecl *OverriddenDD = - cast(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. - continue; - } - } - - if (const CXXDestructorDecl *DD = dyn_cast(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; -} - -uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { - llvm::DenseMap::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 CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) { - MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); - if (I != MethodVtableIndices.end()) - return I->second; - - const CXXRecordDecl *RD = cast(GD.getDecl())->getParent(); - - ComputeMethodVtableIndices(RD); - - I = MethodVtableIndices.find(GD); - assert(I != MethodVtableIndices.end() && "Did not find index!"); - return I->second; -} - -int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { - ClassPairTy ClassPair(RD, VBase); - - VirtualBaseClassOffsetOffsetsMapTy::iterator I = - VirtualBaseClassOffsetOffsets.find(ClassPair); - if (I != VirtualBaseClassOffsetOffsets.end()) - return I->second; - - VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, - BaseSubobject(RD, 0), - /*BaseIsVirtual=*/false, - /*OffsetInLayoutClass=*/0); - - for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = - Builder.getVBaseOffsetOffsets().begin(), - E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { - // Insert all types. - ClassPairTy ClassPair(RD, I->first); - - VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); - } - - I = VirtualBaseClassOffsetOffsets.find(ClassPair); - - // FIXME: The assertion below assertion currently fails with the old vtable - /// layout code if there is a non-virtual thunk adjustment in a vtable. - // Once the new layout is in place, this return should be removed. - if (I == VirtualBaseClassOffsetOffsets.end()) - return 0; - - assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); - - return I->second; -} - -uint64_t -CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) { - uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base)); - assert(AddressPoint && "Address point must not be zero!"); - - return AddressPoint; -} - -llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, - const ThunkInfo &Thunk) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // Compute the mangled name. - llvm::SmallString<256> Name; - if (const CXXDestructorDecl* DD = dyn_cast(MD)) - getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This, - Name); - else - getMangleContext().mangleThunk(MD, Thunk, Name); - - const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); -} - -static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, - llvm::Value *Ptr, - int64_t NonVirtualAdjustment, - int64_t VirtualAdjustment) { - if (!NonVirtualAdjustment && !VirtualAdjustment) - return Ptr; - - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - - llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); - - if (NonVirtualAdjustment) { - // Do the non-virtual adjustment. - V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment); - } - - if (VirtualAdjustment) { - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - - // Do the virtual adjustment. - llvm::Value *VTablePtrPtr = - CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo()); - - llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr); - - llvm::Value *OffsetPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment); - - OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo()); - - // Load the adjustment offset from the vtable. - llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr); - - // Adjust our pointer. - V = CGF.Builder.CreateInBoundsGEP(V, Offset); - } - - // Cast back to the original type. - return CGF.Builder.CreateBitCast(V, Ptr->getType()); -} - -void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, - const ThunkInfo &Thunk) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - const FunctionProtoType *FPT = MD->getType()->getAs(); - QualType ResultType = FPT->getResultType(); - QualType ThisType = MD->getThisType(getContext()); - - FunctionArgList FunctionArgs; - - // FIXME: It would be nice if more of this code could be shared with - // CodeGenFunction::GenerateCode. - - // Create the implicit 'this' parameter declaration. - CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, - MD->getLocation(), - &getContext().Idents.get("this"), - ThisType); - - // Add the 'this' parameter. - FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); - - // Add the rest of the parameters. - for (FunctionDecl::param_const_iterator I = MD->param_begin(), - E = MD->param_end(); I != E; ++I) { - ParmVarDecl *Param = *I; - - FunctionArgs.push_back(std::make_pair(Param, Param->getType())); - } - - StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation()); - - // Adjust the 'this' pointer if necessary. - llvm::Value *AdjustedThisPtr = - PerformTypeAdjustment(*this, LoadCXXThis(), - Thunk.This.NonVirtual, - Thunk.This.VCallOffsetOffset); - - CallArgList CallArgs; - - // Add our adjusted 'this' pointer. - CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType)); - - // Add the rest of the parameters. - for (FunctionDecl::param_const_iterator I = MD->param_begin(), - E = MD->param_end(); I != E; ++I) { - ParmVarDecl *Param = *I; - QualType ArgType = Param->getType(); - - // FIXME: Declaring a DeclRefExpr on the stack is kinda icky. - DeclRefExpr ArgExpr(Param, ArgType.getNonReferenceType(), SourceLocation()); - CallArgs.push_back(std::make_pair(EmitCallArg(&ArgExpr, ArgType), ArgType)); - } - - // Get our callee. - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); - - const CGFunctionInfo &FnInfo = - CGM.getTypes().getFunctionInfo(ResultType, CallArgs, - FPT->getExtInfo()); - - // Now emit our call. - RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD); - - if (!Thunk.Return.isEmpty()) { - // Emit the return adjustment. - bool NullCheckValue = !ResultType->isReferenceType(); - - llvm::BasicBlock *AdjustNull = 0; - llvm::BasicBlock *AdjustNotNull = 0; - llvm::BasicBlock *AdjustEnd = 0; - - llvm::Value *ReturnValue = RV.getScalarVal(); - - if (NullCheckValue) { - AdjustNull = createBasicBlock("adjust.null"); - AdjustNotNull = createBasicBlock("adjust.notnull"); - AdjustEnd = createBasicBlock("adjust.end"); - - llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue); - Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull); - EmitBlock(AdjustNotNull); - } - - ReturnValue = PerformTypeAdjustment(*this, ReturnValue, - Thunk.Return.NonVirtual, - Thunk.Return.VBaseOffsetOffset); - - if (NullCheckValue) { - Builder.CreateBr(AdjustEnd); - EmitBlock(AdjustNull); - Builder.CreateBr(AdjustEnd); - EmitBlock(AdjustEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType()); - PHI->reserveOperandSpace(2); - PHI->addIncoming(ReturnValue, AdjustNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), - AdjustNull); - ReturnValue = PHI; - } - - RV = RValue::get(ReturnValue); - } - - if (!ResultType->isVoidType()) - EmitReturnOfRValue(RV, ResultType); - - FinishFunction(); - - // Destroy the 'this' declaration. - CXXThisDecl->Destroy(getContext()); - - // Set the right linkage. - Fn->setLinkage(CGM.getFunctionLinkage(MD)); - - // Set the right visibility. - CGM.setGlobalVisibility(Fn, MD); -} - -void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) -{ - llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // Strip off a bitcast if we got one back. - if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { - assert(CE->getOpcode() == llvm::Instruction::BitCast); - Entry = CE->getOperand(0); - } - - // There's already a declaration with the same name, check if it has the same - // type or if we need to replace it. - if (cast(Entry)->getType()->getElementType() != - CGM.getTypes().GetFunctionTypeForVtable(MD)) { - llvm::GlobalValue *OldThunkFn = cast(Entry); - - // If the types mismatch then we have to rewrite the definition. - assert(OldThunkFn->isDeclaration() && - "Shouldn't replace non-declaration"); - - // Remove the name from the old thunk function and get a new thunk. - OldThunkFn->setName(llvm::StringRef()); - Entry = CGM.GetAddrOfThunk(GD, Thunk); - - // If needed, replace the old thunk with a bitcast. - if (!OldThunkFn->use_empty()) { - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(Entry, OldThunkFn->getType()); - OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl); - } - - // Remove the old thunk. - OldThunkFn->eraseFromParent(); - } - - // Actually generate the thunk body. - llvm::Function *ThunkFn = cast(Entry); - CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk); -} - -void CodeGenVTables::EmitThunks(GlobalDecl GD) -{ - const CXXMethodDecl *MD = - cast(GD.getDecl())->getCanonicalDecl(); - - // We don't need to generate thunks for the base destructor. - if (isa(MD) && GD.getDtorType() == Dtor_Base) - return; - - const CXXRecordDecl *RD = MD->getParent(); - - // Compute VTable related info for this class. - ComputeVTableRelatedInformation(RD); - - ThunksMapTy::const_iterator I = Thunks.find(MD); - if (I == Thunks.end()) { - // We did not find a thunk for this method. - return; - } - - const ThunkInfoVectorTy &ThunkInfoVector = I->second; - for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I) - EmitThunk(GD, ThunkInfoVector[I]); -} - -void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { - uint64_t *&LayoutData = VTableLayoutMap[RD]; - - // Check if we've computed this information before. - if (LayoutData) - return; - - VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); - - // Add the VTable layout. - uint64_t NumVTableComponents = Builder.getNumVTableComponents(); - LayoutData = new uint64_t[NumVTableComponents + 1]; - - // Store the number of components. - LayoutData[0] = NumVTableComponents; - - // Store the components. - std::copy(Builder.vtable_components_data_begin(), - Builder.vtable_components_data_end(), - &LayoutData[1]); - - // Add the known thunks. - Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); - - // Add the thunks needed in this vtable. - assert(!VTableThunksMap.count(RD) && - "Thunks already exists for this vtable!"); - - VTableThunksTy &VTableThunks = VTableThunksMap[RD]; - VTableThunks.append(Builder.vtable_thunks_begin(), - Builder.vtable_thunks_end()); - - // Sort them. - std::sort(VTableThunks.begin(), VTableThunks.end()); - - // Add the address points. - for (VtableBuilder::AddressPointsMapTy::const_iterator I = - Builder.address_points_begin(), E = Builder.address_points_end(); - I != E; ++I) { - - uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)]; - - // Check if we already have the address points for this base. - assert(!AddressPoint && "Address point already exists for this base!"); - - AddressPoint = I->second; - } - - // If we don't have the vbase information for this class, insert it. - // getVirtualBaseOffsetOffset will compute it separately without computing - // the rest of the vtable related information. - if (!RD->getNumVBases()) - return; - - const RecordType *VBaseRT = - RD->vbases_begin()->getType()->getAs(); - const CXXRecordDecl *VBase = cast(VBaseRT->getDecl()); - - if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) - return; - - for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = - Builder.getVBaseOffsetOffsets().begin(), - E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { - // Insert all types. - ClassPairTy ClassPair(RD, I->first); - - VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); - } -} - -llvm::Constant * -CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, - const uint64_t *Components, - unsigned NumComponents, - const VTableThunksTy &VTableThunks) { - llvm::SmallVector Inits; - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - const llvm::Type *PtrDiffTy = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); - - QualType ClassType = CGM.getContext().getTagDeclType(RD); - llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType); - - unsigned NextVTableThunkIndex = 0; - - llvm::Constant* PureVirtualFn = 0; - - for (unsigned I = 0; I != NumComponents; ++I) { - VtableComponent Component = - VtableComponent::getFromOpaqueInteger(Components[I]); - - llvm::Constant *Init = 0; - - switch (Component.getKind()) { - case VtableComponent::CK_VCallOffset: - Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset()); - Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); - break; - case VtableComponent::CK_VBaseOffset: - Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset()); - Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); - break; - case VtableComponent::CK_OffsetToTop: - Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop()); - Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); - break; - case VtableComponent::CK_RTTI: - Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy); - break; - case VtableComponent::CK_FunctionPointer: - case VtableComponent::CK_CompleteDtorPointer: - case VtableComponent::CK_DeletingDtorPointer: { - GlobalDecl GD; - - // Get the right global decl. - switch (Component.getKind()) { - default: - llvm_unreachable("Unexpected vtable component kind"); - case VtableComponent::CK_FunctionPointer: - GD = Component.getFunctionDecl(); - break; - case VtableComponent::CK_CompleteDtorPointer: - GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete); - break; - case VtableComponent::CK_DeletingDtorPointer: - GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting); - break; - } - - if (cast(GD.getDecl())->isPure()) { - // We have a pure virtual member function. - if (!PureVirtualFn) { - const llvm::FunctionType *Ty = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - /*isVarArg=*/false); - PureVirtualFn = - CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"); - PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn, - Int8PtrTy); - } - - Init = PureVirtualFn; - } else { - // Check if we should use a thunk. - if (NextVTableThunkIndex < VTableThunks.size() && - VTableThunks[NextVTableThunkIndex].first == I) { - const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second; - - Init = CGM.GetAddrOfThunk(GD, Thunk); - - NextVTableThunkIndex++; - } else { - const CXXMethodDecl *MD = cast(GD.getDecl()); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); - - Init = CGM.GetAddrOfFunction(GD, Ty); - } - - Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); - } - break; - } - - case VtableComponent::CK_UnusedFunctionPointer: - Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); - break; - }; - - Inits.push_back(Init); - } - - llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents); - return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size()); -} - -/// GetGlobalVariable - Will return a global variable of the given type. -/// If a variable with a different type already exists then a new variable -/// with the right type will be created. -/// FIXME: We should move this to CodeGenModule and rename it to something -/// better and then use it in CGVTT and CGRTTI. -static llvm::GlobalVariable * -GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, - const llvm::Type *Ty, - llvm::GlobalValue::LinkageTypes Linkage) { - - llvm::GlobalVariable *GV = Module.getNamedGlobal(Name); - llvm::GlobalVariable *OldGV = 0; - - if (GV) { - // Check if the variable has the right type. - if (GV->getType()->getElementType() == Ty) - return GV; - - assert(GV->isDeclaration() && "Declaration has wrong type!"); - - OldGV = GV; - } - - // Create a new variable. - GV = new llvm::GlobalVariable(Module, Ty, /*isConstant=*/true, - Linkage, 0, Name); - - if (OldGV) { - // Replace occurrences of the old variable if needed. - GV->takeName(OldGV); - - if (!OldGV->use_empty()) { - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtrForOldDecl); - } - - OldGV->eraseFromParent(); - } - - return GV; -} - -llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVtable(RD, OutName); - llvm::StringRef Name = OutName.str(); - - ComputeVTableRelatedInformation(RD); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD)); - - return GetGlobalVariable(CGM.getModule(), Name, ArrayType, - llvm::GlobalValue::ExternalLinkage); -} - -void -CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, - llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) { - // Dump the vtable layout if necessary. - if (CGM.getLangOptions().DumpVtableLayouts) { - VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); - - Builder.dumpLayout(llvm::errs()); - } - - assert(VTableThunksMap.count(RD) && - "No thunk status for this record decl!"); - - const VTableThunksTy& Thunks = VTableThunksMap[RD]; - - // Create and set the initializer. - llvm::Constant *Init = - CreateVTableInitializer(RD, getVTableComponentsData(RD), - getNumVTableComponents(RD), Thunks); - VTable->setInitializer(Init); - - // Set the correct linkage. - VTable->setLinkage(Linkage); -} - -llvm::GlobalVariable * -CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, - const BaseSubobject &Base, - bool BaseIsVirtual, - VTableAddressPointsMapTy& AddressPoints) { - VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(), - /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD); - - // Dump the vtable layout if necessary. - if (CGM.getLangOptions().DumpVtableLayouts) - Builder.dumpLayout(llvm::errs()); - - // Add the address points. - AddressPoints.insert(Builder.address_points_begin(), - Builder.address_points_end()); - - // Get the mangled construction vtable name. - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8, - Base.getBase(), OutName); - llvm::StringRef Name = OutName.str(); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents()); - - // Create the variable that will hold the construction vtable. - llvm::GlobalVariable *VTable = - GetGlobalVariable(CGM.getModule(), Name, ArrayType, - llvm::GlobalValue::InternalLinkage); - - // Add the thunks. - VTableThunksTy VTableThunks; - VTableThunks.append(Builder.vtable_thunks_begin(), - Builder.vtable_thunks_end()); - - // Sort them. - std::sort(VTableThunks.begin(), VTableThunks.end()); - - // Create and set the initializer. - llvm::Constant *Init = - CreateVTableInitializer(Base.getBase(), - Builder.vtable_components_data_begin(), - Builder.getNumVTableComponents(), VTableThunks); - VTable->setInitializer(Init); - - return VTable; -} - -void -CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) { - llvm::GlobalVariable *&VTable = Vtables[RD]; - if (VTable) { - assert(VTable->getInitializer() && "Vtable doesn't have a definition!"); - return; - } - - VTable = GetAddrOfVTable(RD); - EmitVTableDefinition(VTable, Linkage, RD); - - GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); -} - -void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - const CXXRecordDecl *RD = MD->getParent(); - - // If the class doesn't have a vtable we don't need to emit one. - if (!RD->isDynamicClass()) - return; - - // Check if we need to emit thunks for this function. - if (MD->isVirtual()) - EmitThunks(GD); - - // Get the key function. - const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); - - TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind(); - TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind(); - - if (KeyFunction) { - // We don't have the right key function. - if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) - return; - } else { - // If we have no key funcion and this is a explicit instantiation declaration, - // we will produce a vtable at the explicit instantiation. We don't need one - // here. - if (RDKind == clang::TSK_ExplicitInstantiationDeclaration) - return; - - // If this is an explicit instantiation of a method, we don't need a vtable. - // Since we have no key function, we will emit the vtable when we see - // a use, and just defining a function is not an use. - if (RDKind == TSK_ImplicitInstantiation && - MDKind == TSK_ExplicitInstantiationDefinition) - return; - } - - if (Vtables.count(RD)) - return; - - if (RDKind == TSK_ImplicitInstantiation) - CGM.DeferredVtables.push_back(RD); - else - GenerateClassData(CGM.getVtableLinkage(RD), RD); -} diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h deleted file mode 100644 index 6073555..0000000 --- a/lib/CodeGen/CGVtable.h +++ /dev/null @@ -1,361 +0,0 @@ -//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code dealing with C++ code generation of virtual tables. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CGVTABLE_H -#define CLANG_CODEGEN_CGVTABLE_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/GlobalVariable.h" -#include "GlobalDecl.h" - -namespace clang { - class CXXRecordDecl; - -namespace CodeGen { - class CodeGenModule; - -/// ReturnAdjustment - A return adjustment. -struct ReturnAdjustment { - /// NonVirtual - The non-virtual adjustment from the derived object to its - /// nearest virtual base. - int64_t NonVirtual; - - /// VBaseOffsetOffset - The offset (in bytes), relative to the address point - /// of the virtual base class offset. - int64_t VBaseOffsetOffset; - - ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } - - bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } - - friend bool operator==(const ReturnAdjustment &LHS, - const ReturnAdjustment &RHS) { - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; - } - - friend bool operator<(const ReturnAdjustment &LHS, - const ReturnAdjustment &RHS) { - if (LHS.NonVirtual < RHS.NonVirtual) - return true; - - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset; - } -}; - -/// ThisAdjustment - A 'this' pointer adjustment. -struct ThisAdjustment { - /// NonVirtual - The non-virtual adjustment from the derived object to its - /// nearest virtual base. - int64_t NonVirtual; - - /// VCallOffsetOffset - The offset (in bytes), relative to the address point, - /// of the virtual call offset. - int64_t VCallOffsetOffset; - - ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } - - bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } - - friend bool operator==(const ThisAdjustment &LHS, - const ThisAdjustment &RHS) { - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; - } - - friend bool operator<(const ThisAdjustment &LHS, - const ThisAdjustment &RHS) { - if (LHS.NonVirtual < RHS.NonVirtual) - return true; - - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VCallOffsetOffset < RHS.VCallOffsetOffset; - } -}; - -/// ThunkInfo - The 'this' pointer adjustment as well as an optional return -/// adjustment for a thunk. -struct ThunkInfo { - /// This - The 'this' pointer adjustment. - ThisAdjustment This; - - /// Return - The return adjustment. - ReturnAdjustment Return; - - ThunkInfo() { } - - ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) - : This(This), Return(Return) { } - - friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { - return LHS.This == RHS.This && LHS.Return == RHS.Return; - } - - friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) { - if (LHS.This < RHS.This) - return true; - - return LHS.This == RHS.This && LHS.Return < RHS.Return; - } - - bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } -}; - -// BaseSubobject - Uniquely identifies a direct or indirect base class. -// Stores both the base class decl and the offset from the most derived class to -// the base class. -class BaseSubobject { - /// Base - The base class declaration. - const CXXRecordDecl *Base; - - /// BaseOffset - The offset from the most derived class to the base class. - uint64_t BaseOffset; - -public: - BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset) - : Base(Base), BaseOffset(BaseOffset) { } - - /// getBase - Returns the base class declaration. - const CXXRecordDecl *getBase() const { return Base; } - - /// getBaseOffset - Returns the base class offset. - uint64_t getBaseOffset() const { return BaseOffset; } - - friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { - return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; - } -}; - -} // end namespace CodeGen -} // end namespace clang - -namespace llvm { - -template<> struct DenseMapInfo { - static clang::CodeGen::BaseSubobject getEmptyKey() { - return clang::CodeGen::BaseSubobject( - DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey()); - } - - static clang::CodeGen::BaseSubobject getTombstoneKey() { - return clang::CodeGen::BaseSubobject( - DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey()); - } - - static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { - return - DenseMapInfo::getHashValue(Base.getBase()) ^ - DenseMapInfo::getHashValue(Base.getBaseOffset()); - } - - static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, - const clang::CodeGen::BaseSubobject &RHS) { - return LHS == RHS; - } -}; - -// It's OK to treat BaseSubobject as a POD type. -template <> struct isPodLike { - static const bool value = true; -}; - -} - -namespace clang { -namespace CodeGen { - -class CodeGenVTables { - 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 MethodVtableIndicesTy; - MethodVtableIndicesTy MethodVtableIndices; - - typedef std::pair ClassPairTy; - - /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to - /// the address point) in bytes where the offsets for virtual bases of a class - /// are stored. - typedef llvm::DenseMap - VirtualBaseClassOffsetOffsetsMapTy; - VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; - - /// Vtables - All the vtables which have been defined. - llvm::DenseMap Vtables; - - /// NumVirtualFunctionPointers - Contains the number of virtual function - /// pointers in the vtable for a given record decl. - llvm::DenseMap NumVirtualFunctionPointers; - - typedef llvm::SmallVector ThunkInfoVectorTy; - typedef llvm::DenseMap ThunksMapTy; - - /// Thunks - Contains all thunks that a given method decl will need. - ThunksMapTy Thunks; - - typedef llvm::DenseMap VTableLayoutMapTy; - - /// VTableLayoutMap - Stores the vtable layout for all record decls. - /// The layout is stored as an array of 64-bit integers, where the first - /// integer is the number of vtable entries in the layout, and the subsequent - /// integers are the vtable components. - VTableLayoutMapTy VTableLayoutMap; - - typedef llvm::DenseMap, uint64_t> AddressPointsMapTy; - - /// Address points - Address points for all vtables. - AddressPointsMapTy AddressPoints; - - /// VTableAddressPointsMapTy - Address points for a single vtable. - typedef llvm::DenseMap VTableAddressPointsMapTy; - - typedef llvm::SmallVector, 1> - VTableThunksTy; - - typedef llvm::DenseMap - VTableThunksMapTy; - - /// VTableThunksMap - Contains thunks needed by vtables. - VTableThunksMapTy VTableThunksMap; - - uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const { - assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); - - return VTableLayoutMap.lookup(RD)[0]; - } - - const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const { - assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!"); - - uint64_t *Components = VTableLayoutMap.lookup(RD); - return &Components[1]; - } - - typedef llvm::DenseMap SubVTTIndiciesMapTy; - - /// SubVTTIndicies - Contains indices into the various sub-VTTs. - SubVTTIndiciesMapTy SubVTTIndicies; - - - typedef llvm::DenseMap, uint64_t> - SecondaryVirtualPointerIndicesMapTy; - - /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer - /// indices. - SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; - - /// 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); - - llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *RD); - - /// EmitThunk - Emit a single thunk. - void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk); - - /// EmitThunks - Emit the associated thunks for the given global decl. - void EmitThunks(GlobalDecl GD); - - /// ComputeVTableRelatedInformation - Compute and store all vtable related - /// information (vtable layout, vbase offset offsets, thunks etc) for the - /// given record decl. - void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); - - /// CreateVTableInitializer - Create a vtable initializer for the given record - /// decl. - /// \param Components - The vtable components; this is really an array of - /// VTableComponents. - llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD, - const uint64_t *Components, - unsigned NumComponents, - const VTableThunksTy &VTableThunks); - -public: - CodeGenVTables(CodeGenModule &CGM) - : CGM(CGM) { } - - /// needsVTTParameter - Return whether the given global decl needs a VTT - /// parameter, which it does if it's a base constructor or destructor with - /// virtual bases. - static bool needsVTTParameter(GlobalDecl GD); - - /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the - /// given record decl. - uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base); - - /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the - /// virtual pointer for the given subobject is located. - uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, - BaseSubobject Base); - - /// getMethodVtableIndex - Return the index (relative to the vtable address - /// point) where the function pointer for the given virtual function is - /// stored. - uint64_t getMethodVtableIndex(GlobalDecl GD); - - /// getVirtualBaseOffsetOffset - Return the offset in bytes (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 getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase); - - /// getAddressPoint - Get the address point of the given subobject in the - /// class decl. - uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); - - /// GetAddrOfVTable - Get the address of the vtable for the given record decl. - llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD); - - /// EmitVTableDefinition - Emit the definition of the given vtable. - void EmitVTableDefinition(llvm::GlobalVariable *VTable, - llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); - - /// GenerateConstructionVTable - Generate a construction vtable for the given - /// base subobject. - llvm::GlobalVariable * - GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, - bool BaseIsVirtual, - VTableAddressPointsMapTy& AddressPoints); - - llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); - - // EmitVTableRelatedData - Will emit any thunks that the global decl might - // have, as well as the vtable itself if the global decl is the key function. - void EmitVTableRelatedData(GlobalDecl GD); - - /// GenerateClassData - Generate all the class data required to be generated - /// upon definition of a KeyFunction. This includes the vtable, the - /// rtti data structure and the VTT. - /// - /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. - void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); -}; - -} // end namespace CodeGen -} // end namespace clang -#endif diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index e72a1d9..dfd2a39 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -23,7 +23,7 @@ add_clang_library(clangCodeGen CGRTTI.cpp CGStmt.cpp CGTemporaries.cpp - CGVtable.cpp + CGVTables.cpp CGVTT.cpp CodeGenFunction.cpp CodeGenModule.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f38d8a1..d3bf164 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -246,15 +246,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { const FunctionDecl *FD = cast(CurGD.getDecl()); - - Stmt *Body = FD->getBody(); - if (Body) - EmitStmt(Body); - else { - assert(FD->isImplicit() && "non-implicit function def has no body"); - assert(FD->isCopyAssignment() && "implicit function not copy assignment"); - SynthesizeCXXCopyAssignment(Args); - } + assert(FD->getBody()); + EmitStmt(FD->getBody()); } void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { @@ -480,6 +473,14 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, } void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { + // Ignore empty classes in C++. + if (getContext().getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs()) { + if (cast(RT->getDecl())->isEmpty()) + return; + } + } + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); @@ -749,6 +750,11 @@ void CodeGenFunction::EmitCleanupBlock() { return; } + // Scrub debug location info. + for (llvm::BasicBlock::iterator LBI = Info.CleanupBlock->begin(), + LBE = Info.CleanupBlock->end(); LBI != LBE; ++LBI) + Builder.SetInstDebugLocation(LBI); + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f21350d..90a3ec4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -32,6 +32,7 @@ namespace llvm { class BasicBlock; class LLVMContext; + class MDNode; class Module; class SwitchInst; class Twine; @@ -148,19 +149,17 @@ public: /// block. class EHCleanupBlock { CodeGenFunction& CGF; - llvm::BasicBlock *Cont; + llvm::BasicBlock *PreviousInsertionBlock; llvm::BasicBlock *CleanupHandler; - llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *PreviousInvokeDest; public: EHCleanupBlock(CodeGenFunction &cgf) - : CGF(cgf), Cont(CGF.createBasicBlock("cont")), - CleanupHandler(CGF.createBasicBlock("ehcleanup")), - CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")), + : CGF(cgf), + PreviousInsertionBlock(CGF.Builder.GetInsertBlock()), + CleanupHandler(CGF.createBasicBlock("ehcleanup", CGF.CurFn)), PreviousInvokeDest(CGF.getInvokeDest()) { - CGF.EmitBranch(Cont); llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - CGF.Builder.SetInsertPoint(CleanupEntryBB); + CGF.Builder.SetInsertPoint(CleanupHandler); CGF.setInvokeDest(TerminateHandler); } ~EHCleanupBlock(); @@ -186,7 +185,8 @@ public: public: DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), + CleanupEntryBB(CGF.createBasicBlock("cleanup")), + CleanupExitBB(0), CurInvokeDest(CGF.getInvokeDest()), EHOnly(ehonly) { CGF.Builder.SetInsertPoint(CleanupEntryBB); @@ -474,11 +474,15 @@ public: /// GenerateObjCGetter - Synthesize an Objective-C property getter function. void GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, + ObjCMethodDecl *MD, bool ctor); /// GenerateObjCSetter - Synthesize an Objective-C property setter function /// for the given property. void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + bool IndirectObjCSetterArg(const CGFunctionInfo &FI); + bool IvarTypeWithAggrGCObjects(QualType Ty); //===--------------------------------------------------------------------===// // Block Bits @@ -532,14 +536,16 @@ public: /// InitializeVTablePointer - Initialize the vtable pointer of the given /// subobject. /// - /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual, + void InitializeVTablePointer(BaseSubobject Base, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass); typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; - void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual, + void InitializeVTablePointers(BaseSubobject Base, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -549,7 +555,6 @@ public: void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); - void SynthesizeCXXCopyAssignment(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 @@ -670,6 +675,9 @@ public: llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, const llvm::Twine &Name = "tmp"); + /// InitTempAlloca - Provide an initial value for the given alloca. + void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value); + /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary /// value needs to be stored into an alloca (for example, to avoid explicit @@ -704,6 +712,12 @@ public: RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false, bool IsInitializer = false); + /// EmitsAnyExprToMem - Emits the code necessary to evaluate an + /// arbitrary expression into the given memory location. + void EmitAnyExprToMem(const Expr *E, llvm::Value *Location, + bool IsLocationVolatile = false, + bool IsInitializer = false); + /// EmitAggregateCopy - Emit an aggrate copy. /// /// \param isVolatile - True iff either the source or the destination is @@ -765,22 +779,23 @@ public: } /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a - /// complete class down to one of its virtual bases. - llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value, - bool IsVirtual, - const CXXRecordDecl *Derived, - const CXXRecordDecl *Base); - + /// complete class to the given direct base. + llvm::Value * + GetAddressOfDirectBaseInCompleteClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base, + bool BaseIsVirtual); + /// GetAddressOfBaseClass - This function will add the necessary delta to the /// load of 'this' and returns address of the base class. - llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, + llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue); - + llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *DerivedClassDecl, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue); llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This, @@ -789,31 +804,17 @@ public: void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); - - void EmitClassAggrCopyAssignment(llvm::Value *DestValue, - llvm::Value *SrcValue, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); + const ConstantArrayType *Array, + const CXXRecordDecl *ClassDecl); void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); - - void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); + const CXXRecordDecl *ClassDecl); void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::Value *This, + bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); @@ -842,7 +843,7 @@ public: llvm::Value *This); void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::Value *This); + bool ForVirtualBase, llvm::Value *This); void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); void PopCXXTemporary(); @@ -1033,6 +1034,7 @@ public: // Note: only availabe for agg return types LValue EmitBinaryOperatorLValue(const BinaryOperator *E); + LValue EmitCompoundAssignOperatorLValue(const CompoundAssignOperator *E); // Note: only available for agg return types LValue EmitCallExprLValue(const CallExpr *E); // Note: only available for agg return types @@ -1100,7 +1102,8 @@ public: llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, - const Decl *TargetDecl = 0); + const Decl *TargetDecl = 0, + llvm::Instruction **callOrInvoke = 0); RValue EmitCall(QualType FnType, llvm::Value *Callee, ReturnValueSlot ReturnValue, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a2ad31e..cc90a28 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -35,6 +35,7 @@ #include "llvm/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Target/TargetData.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace CodeGen; @@ -47,7 +48,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), - MangleCtx(C), VTables(*this), Runtime(0), CFConstantStringClassRef(0), + MangleCtx(C, diags), VTables(*this), Runtime(0), + CFConstantStringClassRef(0), + NSConstantStringClassRef(0), VMContext(M.getContext()) { if (!Features.ObjC1) @@ -78,7 +81,6 @@ void CodeGenModule::createObjCRuntime() { } void CodeGenModule::Release() { - EmitFundamentalRTTIDescriptors(); EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); @@ -313,7 +315,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration) return CodeGenModule::GVA_C99Inline; - + + // If this is a virtual method and its class has a key method in another + // translation unit, we know that this method will be present in that + // translation unit. In this translation unit we will use this method + // only for inlining and analysis. This is the semantics of c99 inline. + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isVirtual() && + CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD)) + return CodeGenModule::GVA_C99Inline; + } + return CodeGenModule::GVA_CXXInline; } @@ -491,11 +504,11 @@ void CodeGenModule::EmitDeferred() { // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. - while (!DeferredDeclsToEmit.empty() || !DeferredVtables.empty()) { - if (!DeferredVtables.empty()) { - const CXXRecordDecl *RD = DeferredVtables.back(); - DeferredVtables.pop_back(); - getVTables().GenerateClassData(getVtableLinkage(RD), RD); + while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) { + if (!DeferredVTables.empty()) { + const CXXRecordDecl *RD = DeferredVTables.back(); + DeferredVTables.pop_back(); + getVTables().GenerateClassData(getVTableLinkage(RD), RD); continue; } @@ -687,30 +700,30 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Defer code generation when possible if this is a static definition, inline // function etc. These we only want to emit if they are used. - if (MayDeferGeneration(Global)) { - // If the value has already been used, add it directly to the - // DeferredDeclsToEmit list. - MangleBuffer MangledName; - getMangledName(MangledName, GD); - if (GetGlobalValue(MangledName)) - DeferredDeclsToEmit.push_back(GD); - else { - // Otherwise, remember that we saw a deferred decl with this name. The - // first use of the mangled name will cause it to move into - // DeferredDeclsToEmit. - DeferredDecls[MangledName] = GD; - } + if (!MayDeferGeneration(Global)) { + // Emit the definition if it can't be deferred. + EmitGlobalDefinition(GD); return; } - - // Otherwise emit the definition. - EmitGlobalDefinition(GD); + + // If the value has already been used, add it directly to the + // DeferredDeclsToEmit list. + MangleBuffer MangledName; + getMangledName(MangledName, GD); + if (GetGlobalValue(MangledName)) + DeferredDeclsToEmit.push_back(GD); + else { + // Otherwise, remember that we saw a deferred decl with this name. The + // first use of the mangled name will cause it to move into + // DeferredDeclsToEmit. + DeferredDecls[MangledName] = GD; + } } void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast(GD.getDecl()); - PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(), + PrettyStackTraceDecl CrashInfo(const_cast(D), D->getLocation(), Context.getSourceManager(), "Generating code for declaration"); @@ -718,16 +731,18 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { getVTables().EmitVTableRelatedData(GD); if (const CXXConstructorDecl *CD = dyn_cast(D)) - EmitCXXConstructor(CD, GD.getCtorType()); - else if (const CXXDestructorDecl *DD = dyn_cast(D)) - EmitCXXDestructor(DD, GD.getDtorType()); - else if (isa(D)) - EmitGlobalFunctionDefinition(GD); - else if (const VarDecl *VD = dyn_cast(D)) - EmitGlobalVarDefinition(VD); - else { - assert(0 && "Invalid argument to EmitGlobalDefinition()"); - } + return EmitCXXConstructor(CD, GD.getCtorType()); + + if (const CXXDestructorDecl *DD = dyn_cast(D)) + return EmitCXXDestructor(DD, GD.getDtorType()); + + if (isa(D)) + return EmitGlobalFunctionDefinition(GD); + + if (const VarDecl *VD = dyn_cast(D)) + return EmitGlobalVarDefinition(VD); + + assert(0 && "Invalid argument to EmitGlobalDefinition()"); } /// GetOrCreateLLVMFunction - If the specified mangled name is not in the @@ -764,12 +779,16 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. bool IsIncompleteFunction = false; - if (!isa(Ty)) { - Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - std::vector(), false); + + const llvm::FunctionType *FTy; + if (isa(Ty)) { + FTy = cast(Ty); + } else { + FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + std::vector(), false); IsIncompleteFunction = true; } - llvm::Function *F = llvm::Function::Create(cast(Ty), + llvm::Function *F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, MangledName, &getModule()); assert(F->getName() == MangledName && "name was uniqued!"); @@ -811,7 +830,14 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, } } - return F; + // Make sure the result is of the requested type. + if (!IsIncompleteFunction) { + assert(F->getType()->getElementType() == Ty); + return F; + } + + const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); + return llvm::ConstantExpr::getBitCast(F, PTy); } /// GetAddrOfFunction - Return the address of the given function. If Ty is @@ -959,7 +985,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { } llvm::GlobalVariable::LinkageTypes -CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) { +CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) return llvm::GlobalVariable::InternalLinkage; @@ -1204,9 +1230,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end(); UI != E; ) { // TODO: Do invokes ever occur in C code? If so, we should handle them too. - unsigned OpNo = UI.getOperandNo(); - llvm::CallInst *CI = dyn_cast(*UI++); - if (!CI || OpNo != 0) continue; + llvm::Value::use_iterator I = UI++; // Increment before the CI is erased. + llvm::CallInst *CI = dyn_cast(*I); + llvm::CallSite CS(CI); + if (!CI || !CS.isCallee(I)) continue; // If the return types don't match exactly, and if the call isn't dead, then // we can't transform this call. @@ -1220,8 +1247,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, bool DontTransform = false; for (llvm::Function::arg_iterator AI = NewFn->arg_begin(), E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) { - if (CI->getNumOperands()-1 == ArgNo || - CI->getOperand(ArgNo+1)->getType() != AI->getType()) { + if (CS.arg_size() == ArgNo || + CS.getArgument(ArgNo)->getType() != AI->getType()) { DontTransform = true; break; } @@ -1231,7 +1258,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, // Okay, we can transform this. Create the new call instruction and copy // over the required information. - ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo); + ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo); llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(), ArgList.end(), "", CI); ArgList.clear(); @@ -1578,6 +1605,90 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { return GV; } +llvm::Constant * +CodeGenModule::GetAddrOfConstantNSString(const StringLiteral *Literal) { + unsigned StringLength = 0; + bool isUTF16 = false; + llvm::StringMapEntry &Entry = + GetConstantCFStringEntry(CFConstantStringMap, Literal, + getTargetData().isLittleEndian(), + isUTF16, StringLength); + + if (llvm::Constant *C = Entry.getValue()) + return C; + + llvm::Constant *Zero = + llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)); + llvm::Constant *Zeros[] = { Zero, Zero }; + + // If we don't already have it, get _NSConstantStringClassReference. + if (!NSConstantStringClassRef) { + const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + Ty = llvm::ArrayType::get(Ty, 0); + llvm::Constant *GV = CreateRuntimeVariable(Ty, + Features.ObjCNonFragileABI ? + "OBJC_CLASS_$_NSConstantString" : + "_NSConstantStringClassReference"); + // Decay array -> ptr + NSConstantStringClassRef = + llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + } + + QualType NSTy = getContext().getNSConstantStringType(); + + const llvm::StructType *STy = + cast(getTypes().ConvertType(NSTy)); + + std::vector Fields(3); + + // Class pointer. + Fields[0] = NSConstantStringClassRef; + + // String pointer. + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); + + llvm::GlobalValue::LinkageTypes Linkage; + bool isConstant; + if (isUTF16) { + // FIXME: why do utf strings get "_" labels instead of "L" labels? + Linkage = llvm::GlobalValue::InternalLinkage; + // Note: -fwritable-strings doesn't make unicode NSStrings writable, but + // does make plain ascii ones writable. + isConstant = true; + } else { + Linkage = llvm::GlobalValue::PrivateLinkage; + isConstant = !Features.WritableStrings; + } + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, + ".str"); + if (isUTF16) { + CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); + GV->setAlignment(Align.getQuantity()); + } + Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + + // String length. + const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); + Fields[2] = llvm::ConstantInt::get(Ty, StringLength); + + // The struct. + C = llvm::ConstantStruct::get(STy, Fields); + GV = new llvm::GlobalVariable(getModule(), C->getType(), true, + llvm::GlobalVariable::PrivateLinkage, C, + "_unnamed_nsstring_"); + // FIXME. Fix section. + if (const char *Sect = + Features.ObjCNonFragileABI + ? getContext().Target.getNSStringNonFragileABISection() + : getContext().Target.getNSStringSection()) + GV->setSection(Sect); + Entry.setValue(GV); + + return GV; +} + /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { @@ -1709,6 +1820,39 @@ void CodeGenModule::EmitObjCPropertyImplementations(const } } +/// EmitObjCIvarInitializations - Emit information for ivar initialization +/// for an implementation. +void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { + if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0) + return; + DeclContext* DC = const_cast(dyn_cast(D)); + assert(DC && "EmitObjCIvarInitializations - null DeclContext"); + IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); + Selector cxxSelector = getContext().Selectors.getSelector(0, &II); + ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), + D->getLocation(), + D->getLocation(), cxxSelector, + getContext().VoidTy, 0, + DC, true, false, true, + ObjCMethodDecl::Required); + D->addInstanceMethod(DTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); + + II = &getContext().Idents.get(".cxx_construct"); + cxxSelector = getContext().Selectors.getSelector(0, &II); + // The constructor returns 'self'. + ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), + D->getLocation(), + D->getLocation(), cxxSelector, + getContext().getObjCIdType(), 0, + DC, true, false, true, + ObjCMethodDecl::Required); + D->addInstanceMethod(CTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); + + +} + /// EmitNamespace - Emit all declarations in a namespace. void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) { for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end(); @@ -1805,6 +1949,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::ObjCImplementation: { ObjCImplementationDecl *OMD = cast(D); EmitObjCPropertyImplementations(OMD); + EmitObjCIvarInitializations(OMD); Runtime->GenerateClass(OMD); break; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index e9f78bc..93d8ddf 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -21,7 +21,7 @@ #include "CGBlocks.h" #include "CGCall.h" #include "CGCXX.h" -#include "CGVtable.h" +#include "CGVTables.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" #include "Mangle.h" @@ -94,7 +94,8 @@ class CodeGenModule : public BlockModule { /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; - + friend class CodeGenVTables; + CGObjCRuntime* Runtime; CGDebugInfo* DebugInfo; @@ -132,6 +133,7 @@ class CodeGenModule : public BlockModule { llvm::StringMap CFConstantStringMap; llvm::StringMap ConstantStringMap; + llvm::DenseMap StaticLocalDeclMap; /// CXXGlobalInits - Global variables with initializers that need to run /// before main. @@ -145,6 +147,10 @@ class CodeGenModule : public BlockModule { /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + /// NSConstantStringClassRef - Cached reference to the class for constant + /// strings. This value has type int * but is actually an Obj-C class pointer. + llvm::Constant *NSConstantStringClassRef; + /// Lazily create the Objective-C runtime void createObjCRuntime(); @@ -169,6 +175,14 @@ public: /// been configured. bool hasObjCRuntime() { return !!Runtime; } + llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) { + return StaticLocalDeclMap[VD]; + } + void setStaticLocalDeclAddress(const VarDecl *D, + llvm::GlobalVariable *GV) { + StaticLocalDeclMap[D] = GV; + } + CGDebugInfo *getDebugInfo() { return DebugInfo; } ASTContext &getContext() const { return Context; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } @@ -218,7 +232,7 @@ public: /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor /// for the given type. - llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty); + llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); /// GetAddrOfThunk - Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); @@ -227,11 +241,11 @@ public: llvm::Constant *GetWeakRefReference(const ValueDecl *VD); /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to - /// its base class. Returns null if the offset is 0. + /// a class. Returns null if the offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl); - + const CXXBaseSpecifierArray &BasePath); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. @@ -240,6 +254,10 @@ public: /// GetAddrOfConstantCFString - Return a pointer to a constant CFString object /// for the given string. llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal); + + /// GetAddrOfConstantNSString - Return a pointer to a constant NSString object + /// for the given string. + llvm::Constant *GetAddrOfConstantNSString(const StringLiteral *Literal); /// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array /// for the given string literal. @@ -416,16 +434,16 @@ public: llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); - /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT, + /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes - getVtableLinkage(const CXXRecordDecl *RD); + getVTableLinkage(const CXXRecordDecl *RD); /// GetTargetTypeStoreSize - Return the store size, in character units, of /// the given LLVM type. CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const; - std::vector DeferredVtables; + std::vector DeferredVTables; private: llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref); @@ -464,6 +482,7 @@ private: void EmitGlobalVarDefinition(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); + void EmitObjCIvarInitializations(ObjCImplementationDecl *D); // C++ related functions. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 9b74106d..10e71e2 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -52,7 +52,6 @@ namespace clang { namespace CodeGen { class CGRecordLayout; - class CodeGenTypes; /// CodeGenTypes - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. @@ -124,10 +123,10 @@ public: const llvm::FunctionType *GetFunctionType(GlobalDecl GD); - /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable, + /// 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 llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD); const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const; diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 077db7c..8658cfb 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -25,7 +25,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" -#include "CGVtable.h" +#include "CGVTables.h" #define MANGLE_CHECKER 0 @@ -111,6 +111,7 @@ public: private: bool mangleSubstitution(const NamedDecl *ND); bool mangleSubstitution(QualType T); + bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); bool mangleStandardSubstitution(const NamedDecl *ND); @@ -121,6 +122,7 @@ private: addSubstitution(reinterpret_cast(ND)); } void addSubstitution(QualType T); + void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); void mangleUnresolvedScope(NestedNameSpecifier *Qualifier); @@ -138,6 +140,7 @@ private: unsigned KnownArity); void mangleUnscopedName(const NamedDecl *ND); void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(TemplateName); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, @@ -147,6 +150,7 @@ private: unsigned NumTemplateArgs); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(TemplateName Template); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); @@ -172,6 +176,9 @@ private: void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); + void mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); void mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -306,8 +313,6 @@ static bool isStd(const NamespaceDecl *NS) { static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { while (isa(DC)) { - assert(cast(DC)->getLanguage() == - LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); DC = DC->getParent(); } @@ -429,6 +434,31 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { addSubstitution(ND); } +void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { + // ::= + // ::= + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleUnscopedTemplateName(TD); + + if (mangleSubstitution(Template)) + return; + + // FIXME: How to cope with operators here? + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Not a dependent template name?"); + if (!Dependent->isIdentifier()) { + // FIXME: We can't possibly know the arity of the operator here! + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle dependent operator name"); + Diags.Report(FullSourceLoc(), DiagID); + return; + } + + mangleSourceName(Dependent->getIdentifier()); + addSubstitution(Template); +} + void CXXNameMangler::mangleNumber(int64_t Number) { // ::= [n] if (Number < 0) { @@ -475,11 +505,12 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { if (const TemplateSpecializationType *TST = dyn_cast(QTy)) { if (!mangleSubstitution(QualType(TST, 0))) { - TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); - assert(TD && "FIXME: Support dependent template names"); - mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TST->getArgs(), + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } @@ -741,6 +772,29 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { addSubstitution(cast(DC)); } +void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { + // ::=