diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-01-01 10:34:51 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-01-01 10:34:51 +0000 |
commit | bb1e3bc1e0be2b8f891db46457a8943451bf4d8b (patch) | |
tree | 1e68501209c9133fbda8d45171e59f8d6f12dd55 /lib/Frontend | |
parent | 77212133072dc40f070a280af8217032f55a9eb4 (diff) | |
download | FreeBSD-src-bb1e3bc1e0be2b8f891db46457a8943451bf4d8b.zip FreeBSD-src-bb1e3bc1e0be2b8f891db46457a8943451bf4d8b.tar.gz |
Updaet clang to 92395.
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/AnalysisConsumer.cpp | 57 | ||||
-rw-r--r-- | lib/Frontend/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 24 | ||||
-rw-r--r-- | lib/Frontend/FrontendActions.cpp | 5 | ||||
-rw-r--r-- | lib/Frontend/InitHeaderSearch.cpp | 13 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 17 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderStmt.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 19 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterStmt.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/RewriteBlocks.cpp | 1152 | ||||
-rw-r--r-- | lib/Frontend/RewriteObjC.cpp | 241 | ||||
-rw-r--r-- | lib/Frontend/Warnings.cpp | 37 |
12 files changed, 317 insertions, 1253 deletions
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index a74bbc2..6824d8f 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -14,10 +14,10 @@ #include "clang/Frontend/AnalysisConsumer.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/ManagerRegistry.h" @@ -228,6 +228,19 @@ void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { break; } + case Decl::CXXMethod: { + CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); + + if (Opts.AnalyzeSpecificFunction.size() > 0 && + Opts.AnalyzeSpecificFunction != CXXMD->getName()) + return; + + Stmt *Body = CXXMD->getBody(); + if (Body) + HandleCode(CXXMD, Body, FunctionActions); + break; + } + default: break; } @@ -240,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { if (!TranslationUnitActions.empty()) { // Find the entry function definition (if any). FunctionDecl *FD = 0; - + // Must specify an entry function. if (!Opts.AnalyzeSpecificFunction.empty()) { for (DeclContext::decl_iterator I=TU->decls_begin(), E=TU->decls_end(); I != E; ++I) { @@ -253,9 +266,11 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { } } - for (Actions::iterator I = TranslationUnitActions.begin(), - E = TranslationUnitActions.end(); I != E; ++I) - (*I)(*this, *Mgr, FD); + if (FD) { + for (Actions::iterator I = TranslationUnitActions.begin(), + E = TranslationUnitActions.end(); I != E; ++I) + (*I)(*this, *Mgr, FD); + } } if (!ObjCImplementationActions.empty()) { @@ -358,7 +373,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - Eng.setTransferFunctions(tf); + Eng.setTransferFunctionsAndCheckers(tf); // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; @@ -475,8 +490,36 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { + // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup. + // Display progress. + C.DisplayFunction(D); + + GRExprEngine Eng(mgr); + + if (C.Opts.EnableExperimentalInternalChecks) + RegisterExperimentalInternalChecks(Eng); - ActionGRExprEngine(C, mgr, D, CreateCallInliner(mgr.getASTContext())); + RegisterAppleChecks(Eng, *D); + + if (C.Opts.EnableExperimentalChecks) + RegisterExperimentalChecks(Eng); + + // Make a fake transfer function. The GRTransferFunc interface will be + // removed. + Eng.setTransferFunctionsAndCheckers(new GRTransferFuncs()); + + // Register call inliner as the last checker. + RegisterCallInliner(Eng); + + // Execute the worklist algorithm. + Eng.ExecuteWorkList(mgr.getStackFrame(D)); + + // Visualize the exploded graph. + if (mgr.shouldVisualizeGraphviz()) + Eng.ViewGraph(mgr.shouldTrimGraph()); + + // Display warnings. + Eng.getBugReporter().FlushReports(); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 03123d3..58aaa43 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -31,7 +31,6 @@ add_clang_library(clangFrontend PlistDiagnostics.cpp PrintParserCallbacks.cpp PrintPreprocessedOutput.cpp - RewriteBlocks.cpp RewriteMacros.cpp RewriteObjC.cpp RewriteTest.cpp diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7a3388f..63f66fa 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -122,6 +122,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-disable-llvm-optzns"); if (Opts.DisableRedZone) Res.push_back("-disable-red-zone"); + if (!Opts.DwarfDebugFlags.empty()) { + Res.push_back("-dwarf-debug-flags"); + Res.push_back(Opts.DwarfDebugFlags); + } if (!Opts.MergeAllConstants) Res.push_back("-fno-merge-all-constants"); if (Opts.NoCommon) @@ -276,7 +280,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ParseSyntaxOnly: return "-fsyntax-only"; case frontend::PrintDeclContext: return "-print-decl-contexts"; case frontend::PrintPreprocessedInput: return "-E"; - case frontend::RewriteBlocks: return "-rewrite-blocks"; case frontend::RewriteMacros: return "-rewrite-macros"; case frontend::RewriteObjC: return "-rewrite-objc"; case frontend::RewriteTest: return "-rewrite-test"; @@ -440,7 +443,7 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.DollarIdents) Res.push_back("-fdollars-in-identifiers"); if (Opts.Microsoft) - Res.push_back("-fms-extensions=1"); + Res.push_back("-fms-extensions"); if (Opts.ObjCNonFragileABI) Res.push_back("-fobjc-nonfragile-abi"); // NoInline is implicit. @@ -466,6 +469,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-ffreestanding"); if (Opts.NoBuiltin) Res.push_back("-fno-builtin"); + if (!Opts.AssumeSaneOperatorNew) + Res.push_back("-fno-assume-sane-operator-new"); if (Opts.ThreadsafeStatics) llvm::llvm_report_error("FIXME: Not yet implemented!"); if (Opts.POSIXThreads) @@ -593,7 +598,7 @@ static void TargetOptsToArgs(const TargetOptions &Opts, Res.push_back("-triple"); Res.push_back(Opts.Triple); if (!Opts.CPU.empty()) { - Res.push_back("-mcpu"); + Res.push_back("-target-cpu"); Res.push_back(Opts.CPU); } if (!Opts.ABI.empty()) { @@ -747,6 +752,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.DebugInfo = Args.hasArg(OPT_g); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.DwarfDebugFlags = getLastArgValue(Args, OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); @@ -851,8 +857,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::PrintDeclContext; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; - case OPT_rewrite_blocks: - Opts.ProgramAction = frontend::RewriteBlocks; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: @@ -1124,10 +1128,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_trigraphs)) Opts.Trigraphs = 1; - Opts.DollarIdents = !Opts.AsmPreprocessor; - if (Args.hasArg(OPT_fdollars_in_identifiers)) - Opts.DollarIdents = 1; - + Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, + OPT_fno_dollars_in_identifiers, + !Opts.AsmPreprocessor); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); Opts.Microsoft = Args.hasArg(OPT_fms_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); @@ -1140,6 +1143,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = Args.hasArg(OPT_faccess_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); @@ -1245,7 +1249,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.ABI = getLastArgValue(Args, OPT_target_abi); - Opts.CPU = getLastArgValue(Args, OPT_mcpu); + Opts.CPU = getLastArgValue(Args, OPT_target_cpu); Opts.Triple = getLastArgValue(Args, OPT_triple); Opts.Features = getAllArgValues(Args, OPT_target_feature); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index e3c313a..4c647fda 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -154,11 +154,6 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, return 0; } -ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts()); -} - ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { return new ASTConsumer(); diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index b4ea257..9555125 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -478,6 +478,14 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::Linux: + // Exherbo (2009-10-26) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-pc-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-pc-linux-gnu", "", "", triple); + // Debian sid + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-linux-gnu", "32", "", triple); // Ubuntu 7.10 - Gutsy Gibbon AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", "i486-linux-gnu", "", "", triple); @@ -543,11 +551,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", "i686-pc-linux-gnu", "", "", triple); - // Exherbo (2009-10-26) - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "x86_64-pc-linux-gnu", "32", "", triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", - "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: // DragonFly diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 48ef2ac..d8fd791 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1761,11 +1761,6 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getQualifiedType(Base, Quals); } - case pch::TYPE_FIXED_WIDTH_INT: { - assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type"); - return Context->getFixedWidthIntType(Record[0], Record[1]); - } - case pch::TYPE_COMPLEX: { assert(Record.size() == 1 && "Incorrect encoding of complex type"); QualType ElemType = GetType(Record[0]); @@ -1854,17 +1849,18 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 1) { + if (Record.size() != 2) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - return Context->getFunctionNoProtoType(ResultType); + return Context->getFunctionNoProtoType(ResultType, Record[1]); } case pch::TYPE_FUNCTION_PROTO: { QualType ResultType = GetType(Record[0]); - unsigned Idx = 1; + bool NoReturn = Record[1]; + unsigned Idx = 2; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -1880,7 +1876,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, isVariadic, Quals, hasExceptionSpec, hasAnyExceptionSpec, NumExceptions, - Exceptions.data()); + Exceptions.data(), NoReturn); } case pch::TYPE_UNRESOLVED_USING: @@ -1986,9 +1982,6 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } -void TypeLocReader::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index f28e61e..ba82d26 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -858,7 +858,9 @@ unsigned PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setElidable(Record[Idx++]); + E->setRequiresZeroInitialization(Record[Idx++]); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); return E->getNumArgs(); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 681c1ff..2875f09 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -69,12 +69,6 @@ void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { assert(false && "Built-in types are never serialized"); } -void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) { - Record.push_back(T->getWidth()); - Record.push_back(T->isSigned()); - Code = pch::TYPE_FIXED_WIDTH_INT; -} - void PCHTypeWriter::VisitComplexType(const ComplexType *T) { Writer.AddTypeRef(T->getElementType(), Record); Code = pch::TYPE_COMPLEX; @@ -144,6 +138,7 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); + Record.push_back(T->getNoReturnAttr()); } void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { @@ -282,9 +277,6 @@ void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } -void TypeLocWriter::VisitFixedWidthIntTypeLoc(FixedWidthIntTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -558,7 +550,6 @@ void PCHWriter::WriteBlockInfoBlock() { // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); - RECORD(TYPE_FIXED_WIDTH_INT); RECORD(TYPE_COMPLEX); RECORD(TYPE_POINTER); RECORD(TYPE_BLOCK_POINTER); @@ -1645,10 +1636,10 @@ public: II->hasMacroDefinition() && !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro(); Bits = (uint32_t)II->getObjCOrBuiltinID(); - Bits = (Bits << 1) | hasMacroDefinition; - Bits = (Bits << 1) | II->isExtensionToken(); - Bits = (Bits << 1) | II->isPoisoned(); - Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword(); + Bits = (Bits << 1) | unsigned(hasMacroDefinition); + Bits = (Bits << 1) | unsigned(II->isExtensionToken()); + Bits = (Bits << 1) | unsigned(II->isPoisoned()); + Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); clang::io::Emit16(Out, Bits); if (hasMacroDefinition) diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 22f7ad6..abf4eaa 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -785,7 +785,9 @@ void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getConstructor(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); Record.push_back(E->isElidable()); + Record.push_back(E->requiresZeroInitialization()); Record.push_back(E->getNumArgs()); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) Writer.WriteSubStmt(E->getArg(I)); diff --git a/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp deleted file mode 100644 index 25e7fc4..0000000 --- a/lib/Frontend/RewriteBlocks.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -//===--- RewriteBlocks.cpp ----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hacks and fun related to the closure rewriter. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LangOptions.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/SmallPtrSet.h" - -using namespace clang; -using llvm::utostr; - -namespace { - -class RewriteBlocks : public ASTConsumer { - Rewriter Rewrite; - Diagnostic &Diags; - const LangOptions &LangOpts; - unsigned RewriteFailedDiag; - - ASTContext *Context; - SourceManager *SM; - FileID MainFileID; - const char *MainFileStart, *MainFileEnd; - - // Block expressions. - llvm::SmallVector<BlockExpr *, 32> Blocks; - llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs; - llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs; - - // Block related declarations. - llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls; - llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls; - llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; - - llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; - - // The function/method we are rewriting. - FunctionDecl *CurFunctionDef; - ObjCMethodDecl *CurMethodDef; - - bool IsHeader; - - std::string Preamble; -public: - RewriteBlocks(std::string inFile, Diagnostic &D, - const LangOptions &LOpts); - ~RewriteBlocks() { - // Get the buffer corresponding to MainFileID. - // If we haven't changed it, then we are done. - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - std::string S(RewriteBuf->begin(), RewriteBuf->end()); - printf("%s\n", S.c_str()); - } else { - printf("No changes\n"); - } - } - - void Initialize(ASTContext &context); - - void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen); - void ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength); - - // Top Level Driver code. - virtual void HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) - HandleTopLevelSingleDecl(*I); - } - void HandleTopLevelSingleDecl(Decl *D); - void HandleDeclInMainFile(Decl *D); - - // Top level - Stmt *RewriteFunctionBody(Stmt *S); - void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); - void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); - - // Block specific rewrite rules. - std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0); - - void RewriteBlockCall(CallExpr *Exp); - void RewriteBlockPointerDecl(NamedDecl *VD); - void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD); - void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); - - std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - const char *funcName, std::string Tag); - std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - const char *funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers); - std::string SynthesizeBlockCall(CallExpr *Exp); - void SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName); - - void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockCallExprs(Stmt *S); - void GetBlockDeclRefExprs(Stmt *S); - - // We avoid calling Type::isBlockPointerType(), since it operates on the - // canonical type. We only care if the top-level type is a closure pointer. - bool isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); } - - // FIXME: This predicate seems like it would be useful to add to ASTContext. - bool isObjCType(QualType T) { - if (!LangOpts.ObjC1 && !LangOpts.ObjC2) - return false; - - QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); - - if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || - OCT == Context->getCanonicalType(Context->getObjCClassType())) - return true; - - if (const PointerType *PT = OCT->getAs<PointerType>()) { - if (isa<ObjCInterfaceType>(PT->getPointeeType()) || - PT->getPointeeType()->isObjCQualifiedIdType()) - return true; - } - return false; - } - // ObjC rewrite methods. - void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl); - void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl); - void RewriteProtocolDecl(ObjCProtocolDecl *PDecl); - void RewriteMethodDecl(ObjCMethodDecl *MDecl); - - void RewriteFunctionProtoType(QualType funcType, NamedDecl *D); - void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); - void RewriteCastExpr(CastExpr *CE); - - bool PointerTypeTakesAnyBlockArguments(QualType QT); - void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen); -}; - -} - -static bool IsHeaderFile(const std::string &Filename) { - std::string::size_type DotPos = Filename.rfind('.'); - - if (DotPos == std::string::npos) { - // no file extension - return false; - } - - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); - // C header: .h - // C++ header: .hh or .H; - return Ext == "h" || Ext == "hh" || Ext == "H"; -} - -RewriteBlocks::RewriteBlocks(std::string inFile, - Diagnostic &D, const LangOptions &LOpts) : - Diags(D), LangOpts(LOpts) { - IsHeader = IsHeaderFile(inFile); - CurFunctionDef = 0; - CurMethodDef = 0; - RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, - "rewriting failed"); -} - -ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile, - Diagnostic &Diags, - const LangOptions &LangOpts) { - return new RewriteBlocks(InFile, Diags, LangOpts); -} - -void RewriteBlocks::Initialize(ASTContext &context) { - Context = &context; - SM = &Context->getSourceManager(); - - // Get the ID and start/end of the main file. - MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); - - Rewrite.setSourceMgr(Context->getSourceManager(), LangOpts); - - if (IsHeader) - Preamble = "#pragma once\n"; - Preamble += "#ifndef BLOCK_IMPL\n"; - Preamble += "#define BLOCK_IMPL\n"; - Preamble += "struct __block_impl {\n"; - Preamble += " void *isa;\n"; - Preamble += " int Flags;\n"; - Preamble += " int Size;\n"; - Preamble += " void *FuncPtr;\n"; - Preamble += "};\n"; - Preamble += "enum {\n"; - Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n"; - Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n"; - Preamble += "};\n"; - if (LangOpts.Microsoft) - Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n"; - else - Preamble += "#define __OBJC_RW_EXTERN extern\n"; - Preamble += "// Runtime copy/destroy helper functions\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n"; - Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n"; - Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n"; - Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n"; - Preamble += "#endif\n"; - - InsertText(SM->getLocForStartOfFile(MainFileID), - Preamble.c_str(), Preamble.size()); -} - -void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData, - unsigned StrLen) { - if (!Rewrite.InsertText(Loc, StrData, StrLen)) - return; - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); -} - -void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength) { - if (!Rewrite.ReplaceText(Start, OrigLength, - llvm::StringRef(NewStr, NewLength))) - return; - Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); -} - -void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) { - bool haveBlockPtrs = false; - for (ObjCMethodDecl::param_iterator I = Method->param_begin(), - E = Method->param_end(); I != E; ++I) - if (isBlockPointerType((*I)->getType())) - haveBlockPtrs = true; - - if (!haveBlockPtrs) - return; - - // Do a fuzzy rewrite. - // We have 1 or more arguments that have closure pointers. - SourceLocation Loc = Method->getLocStart(); - SourceLocation LocEnd = Method->getLocEnd(); - const char *startBuf = SM->getCharacterData(Loc); - const char *endBuf = SM->getCharacterData(LocEnd); - - const char *methodPtr = startBuf; - std::string Tag = "struct __block_impl *"; - - while (*methodPtr++ && (methodPtr != endBuf)) { - switch (*methodPtr) { - case ':': - methodPtr++; - if (*methodPtr == '(') { - const char *scanType = ++methodPtr; - bool foundBlockPointer = false; - unsigned parenCount = 1; - - while (parenCount) { - switch (*scanType) { - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - case '^': - foundBlockPointer = true; - break; - } - scanType++; - } - if (foundBlockPointer) { - // advance the location to startArgList. - Loc = Loc.getFileLocWithOffset(methodPtr-startBuf); - assert((Loc.isValid()) && "Invalid Loc"); - ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size()); - - // Advance startBuf. Since the underlying buffer has changed, - // it's very important to advance startBuf (so we can correctly - // compute a relative Loc the next time around). - startBuf = methodPtr; - } - // Advance the method ptr to the end of the type. - methodPtr = scanType; - } - break; - } - } - return; -} - -void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { - for (ObjCInterfaceDecl::instmeth_iterator - I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); - for (ObjCInterfaceDecl::classmeth_iterator - I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); -} - -void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { - for (ObjCCategoryDecl::instmeth_iterator - I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); - for (ObjCCategoryDecl::classmeth_iterator - I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); -} - -void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - for (ObjCProtocolDecl::instmeth_iterator - I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); - for (ObjCProtocolDecl::classmeth_iterator - I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); - I != E; ++I) - RewriteMethodDecl(*I); -} - -//===----------------------------------------------------------------------===// -// Top Level Driver Code -//===----------------------------------------------------------------------===// - -void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) { - // Two cases: either the decl could be in the main file, or it could be in a - // #included file. If the former, rewrite it now. If the later, check to see - // if we rewrote the #include/#import. - SourceLocation Loc = D->getLocation(); - Loc = SM->getInstantiationLoc(Loc); - - // If this is for a builtin, ignore it. - if (Loc.isInvalid()) return; - - if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) - RewriteInterfaceDecl(MD); - else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) - RewriteCategoryDecl(CD); - else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) - RewriteProtocolDecl(PD); - - // If we have a decl in the main file, see if we should rewrite it. - if (SM->isFromMainFile(Loc)) - HandleDeclInMainFile(D); - return; -} - -std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i, - const char *funcName, - std::string Tag) { - const FunctionType *AFT = CE->getFunctionType(); - QualType RT = AFT->getResultType(); - std::string StructRef = "struct " + Tag; - std::string S = "static " + RT.getAsString() + " __" + - funcName + "_" + "block_func_" + utostr(i); - - BlockDecl *BD = CE->getBlockDecl(); - - if (isa<FunctionNoProtoType>(AFT)) { - S += "()"; - } else if (BD->param_empty()) { - S += "(" + StructRef + " *__cself)"; - } else { - const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); - assert(FT && "SynthesizeBlockFunc: No function proto"); - S += '('; - // first add the implicit argument. - S += StructRef + " *__cself, "; - std::string ParamStr; - for (BlockDecl::param_iterator AI = BD->param_begin(), - E = BD->param_end(); AI != E; ++AI) { - if (AI != BD->param_begin()) S += ", "; - ParamStr = (*AI)->getNameAsString(); - (*AI)->getType().getAsStringInternal(ParamStr, Context->PrintingPolicy); - S += ParamStr; - } - if (FT->isVariadic()) { - if (!BD->param_empty()) S += ", "; - S += "..."; - } - S += ')'; - } - S += " {\n"; - - // Create local declarations to avoid rewriting all closure decl ref exprs. - // First, emit a declaration for all "by ref" decls. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - Context->getPointerType((*I)->getType()).getAsStringInternal(Name, - Context->PrintingPolicy); - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; - } - // Next, emit a declaration for all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string Name = (*I)->getNameAsString(); - // Handle nested closure invocation. For example: - // - // void (^myImportedClosure)(void); - // myImportedClosure = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherClosure)(void); - // anotherClosure = ^(void) { - // myImportedClosure(); // import and invoke the closure - // }; - // - if (isBlockPointerType((*I)->getType())) - S += "struct __block_impl *"; - else - (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy); - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - std::string RewrittenStr = RewrittenBlockExprs[CE]; - const char *cstr = RewrittenStr.c_str(); - while (*cstr++ != '{') ; - S += cstr; - S += "\n"; - return S; -} - -std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - const char *funcName, - std::string Tag) { - std::string StructRef = "struct " + Tag; - std::string S = "static void __"; - - S += funcName; - S += "_block_copy_" + utostr(i); - S += "(" + StructRef; - S += "*dst, " + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - S += "_Block_copy_assign(&dst->"; - S += (*I)->getNameAsString(); - S += ", src->"; - S += (*I)->getNameAsString(); - S += ");}"; - } - S += "\nstatic void __"; - S += funcName; - S += "_block_dispose_" + utostr(i); - S += "(" + StructRef; - S += "*src) {"; - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), - E = ImportedBlockDecls.end(); I != E; ++I) { - S += "_Block_destroy(src->"; - S += (*I)->getNameAsString(); - S += ");"; - } - S += "}\n"; - return S; -} - -std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers) { - std::string S = "struct " + Tag; - std::string Constructor = " " + Tag; - - S += " {\n struct __block_impl impl;\n"; - - if (hasCopyDisposeHelpers) - S += " void *copy;\n void *dispose;\n"; - - Constructor += "(void *fp"; - - if (hasCopyDisposeHelpers) - Constructor += ", void *copyHelp, void *disposeHelp"; - - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy); - (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy); - Constructor += ", " + ArgName; - } - S += FieldName + ";\n"; - } - // Output all "by ref" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - S += " "; - std::string FieldName = (*I)->getNameAsString(); - std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { - Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName, - Context->PrintingPolicy); - Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName, - Context->PrintingPolicy); - Constructor += ", " + ArgName; - } - S += FieldName + "; // by ref\n"; - } - // Finish writing the constructor. - // FIXME: handle NSConcreteGlobalBlock. - Constructor += ", int flags=0) {\n"; - Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; - - // Initialize all "by copy" arguments. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - Constructor += " "; - if (isBlockPointerType((*I)->getType())) - Constructor += Name + " = (struct __block_impl *)_"; - else - Constructor += Name + " = _"; - Constructor += Name + ";\n"; - } - // Initialize all "by ref" arguments. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - Constructor += " "; - if (isBlockPointerType((*I)->getType())) - Constructor += Name + " = (struct __block_impl *)_"; - else - Constructor += Name + " = _"; - Constructor += Name + ";\n"; - } - } else { - // Finish writing the constructor. - // FIXME: handle NSConcreteGlobalBlock. - Constructor += ", int flags=0) {\n"; - Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; - } - Constructor += " "; - Constructor += "}\n"; - S += Constructor; - S += "};\n"; - return S; -} - -void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName) { - // Insert closures that were part of the function. - for (unsigned i = 0; i < Blocks.size(); i++) { - - CollectBlockDeclRefInfo(Blocks[i]); - - std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); - - std::string CI = SynthesizeBlockImpl(Blocks[i], Tag, - ImportedBlockDecls.size() > 0); - - InsertText(FunLocStart, CI.c_str(), CI.size()); - - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag); - - InsertText(FunLocStart, CF.c_str(), CF.size()); - - if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag); - InsertText(FunLocStart, HF.c_str(), HF.size()); - } - - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByCopyDecls.clear(); - BlockCallExprs.clear(); - ImportedBlockDecls.clear(); - } - Blocks.clear(); - RewrittenBlockExprs.clear(); -} - -void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { - SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const char *FuncName = FD->getNameAsCString(); - - SynthesizeBlockLiterals(FunLocStart, FuncName); -} - -void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { - SourceLocation FunLocStart = MD->getLocStart(); - std::string FuncName = MD->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = FuncName.find(":", loc)) != std::string::npos) - FuncName.replace(loc, 1, "_"); - - SynthesizeBlockLiterals(FunLocStart, FuncName.c_str()); -} - -void RewriteBlocks::GetBlockDeclRefExprs(Stmt *S) { - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) - GetBlockDeclRefExprs(CBE->getBody()); - else - GetBlockDeclRefExprs(*CI); - } - // Handle specific things. - if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) - // FIXME: Handle enums. - if (!isa<FunctionDecl>(CDRE->getDecl())) - BlockDeclRefs.push_back(CDRE); - return; -} - -void RewriteBlocks::GetBlockCallExprs(Stmt *S) { - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) - GetBlockCallExprs(CBE->getBody()); - else - GetBlockCallExprs(*CI); - } - - if (CallExpr *CE = dyn_cast<CallExpr>(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE; - } - } - return; -} - -std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) { - // Navigate to relevant type information. - const char *closureName = 0; - const BlockPointerType *CPT = 0; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) { - closureName = DRE->getDecl()->getNameAsCString(); - CPT = DRE->getType()->getAs<BlockPointerType>(); - } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) { - closureName = CDRE->getDecl()->getNameAsCString(); - CPT = CDRE->getType()->getAs<BlockPointerType>(); - } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) { - closureName = MExpr->getMemberDecl()->getNameAsCString(); - CPT = MExpr->getType()->getAs<BlockPointerType>(); - } else { - assert(1 && "RewriteBlockClass: Bad type"); - } - assert(CPT && "RewriteBlockClass: Bad type"); - const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>(); - assert(FT && "RewriteBlockClass: Bad type"); - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); - // FTP will be null for closures that don't take arguments. - - // Build a closure call - start with a paren expr to enforce precedence. - std::string BlockCall = "("; - - // Synthesize the cast. - BlockCall += "(" + Exp->getType().getAsString() + "(*)"; - BlockCall += "(struct __block_impl *"; - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I && (I != E); ++I) - BlockCall += ", " + (*I).getAsString(); - } - BlockCall += "))"; // close the argument list and paren expression. - - // Invoke the closure. We need to cast it since the declaration type is - // bogus (it's a function pointer type) - BlockCall += "((struct __block_impl *)"; - std::string closureExprBufStr; - llvm::raw_string_ostream closureExprBuf(closureExprBufStr); - Exp->getCallee()->printPretty(closureExprBuf, *Context, 0, - PrintingPolicy(LangOpts)); - BlockCall += closureExprBuf.str(); - BlockCall += ")->FuncPtr)"; - - // Add the arguments. - BlockCall += "((struct __block_impl *)"; - BlockCall += closureExprBuf.str(); - for (CallExpr::arg_iterator I = Exp->arg_begin(), - E = Exp->arg_end(); I != E; ++I) { - std::string syncExprBufS; - llvm::raw_string_ostream Buf(syncExprBufS); - (*I)->printPretty(Buf, *Context, 0, PrintingPolicy(LangOpts)); - BlockCall += ", " + Buf.str(); - } - return BlockCall; -} - -void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) { - std::string BlockCall = SynthesizeBlockCall(Exp); - - const char *startBuf = SM->getCharacterData(Exp->getLocStart()); - const char *endBuf = SM->getCharacterData(Exp->getLocEnd()); - - ReplaceText(Exp->getLocStart(), endBuf-startBuf, - BlockCall.c_str(), BlockCall.size()); -} - -void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) { - // FIXME: Add more elaborate code generation required by the ABI. - InsertText(BDRE->getLocStart(), "*", 1); -} - -void RewriteBlocks::RewriteCastExpr(CastExpr *CE) { - SourceLocation LocStart = CE->getLocStart(); - SourceLocation LocEnd = CE->getLocEnd(); - - if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) - return; - - const char *startBuf = SM->getCharacterData(LocStart); - const char *endBuf = SM->getCharacterData(LocEnd); - - // advance the location to startArgList. - const char *argPtr = startBuf; - - while (*argPtr++ && (argPtr < endBuf)) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*", 1); - break; - } - } - return; -} - -void RewriteBlocks::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { - SourceLocation DeclLoc = FD->getLocation(); - unsigned parenCount = 0; - - // We have 1 or more arguments that have closure pointers. - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *startArgList = strchr(startBuf, '('); - - assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); - - parenCount++; - // advance the location to startArgList. - DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf); - assert((DeclLoc.isValid()) && "Invalid DeclLoc"); - - const char *argPtr = startArgList; - - while (*argPtr++ && parenCount) { - switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*", 1); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; - } - } - return; -} - -bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) { - const FunctionProtoType *FTP; - const PointerType *PT = QT->getAs<PointerType>(); - if (PT) { - FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); - } else { - const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); - assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); - FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); - } - if (FTP) { - for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), - E = FTP->arg_type_end(); I != E; ++I) - if (isBlockPointerType(*I)) - return true; - } - return false; -} - -void RewriteBlocks::GetExtentOfArgList(const char *Name, - const char *&LParen, const char *&RParen) { - const char *argPtr = strchr(Name, '('); - assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); - - LParen = argPtr; // output the start. - argPtr++; // skip past the left paren. - unsigned parenCount = 1; - - while (*argPtr && parenCount) { - switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; - } - if (parenCount) argPtr++; - } - assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); - RParen = argPtr; // output the end -} - -void RewriteBlocks::RewriteBlockPointerDecl(NamedDecl *ND) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - RewriteBlockPointerFunctionArgs(FD); - return; - } - // Handle Variables and Typedefs. - SourceLocation DeclLoc = ND->getLocation(); - QualType DeclT; - if (VarDecl *VD = dyn_cast<VarDecl>(ND)) - DeclT = VD->getType(); - else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) - DeclT = TDD->getUnderlyingType(); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) - DeclT = FD->getType(); - else - assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled"); - - const char *startBuf = SM->getCharacterData(DeclLoc); - const char *endBuf = startBuf; - // scan backward (from the decl location) for the end of the previous decl. - while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) - startBuf--; - - // *startBuf != '^' if we are dealing with a pointer to function that - // may take block argument types (which will be handled below). - if (*startBuf == '^') { - // Replace the '^' with '*', computing a negative offset. - DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf); - ReplaceText(DeclLoc, 1, "*", 1); - } - if (PointerTypeTakesAnyBlockArguments(DeclT)) { - // Replace the '^' with '*' for arguments. - DeclLoc = ND->getLocation(); - startBuf = SM->getCharacterData(DeclLoc); - const char *argListBegin, *argListEnd; - GetExtentOfArgList(startBuf, argListBegin, argListEnd); - while (argListBegin < argListEnd) { - if (*argListBegin == '^') { - SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf); - ReplaceText(CaretLoc, 1, "*", 1); - } - argListBegin++; - } - } - return; -} - -void RewriteBlocks::CollectBlockDeclRefInfo(BlockExpr *Exp) { - // Add initializers for any closure decl refs. - GetBlockDeclRefExprs(Exp->getBody()); - if (BlockDeclRefs.size()) { - // Unique all "by copy" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->isByRef()) - BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl()); - // Unique all "by ref" declarations. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->isByRef()) { - BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl()); - } - // Find any imported blocks...they will need special attention. - for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (isBlockPointerType(BlockDeclRefs[i]->getType())) { - GetBlockCallExprs(Blocks[i]); - ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } - } -} - -std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) { - Blocks.push_back(Exp); - - CollectBlockDeclRefInfo(Exp); - std::string FuncName; - - if (CurFunctionDef) - FuncName = std::string(CurFunctionDef->getNameAsString()); - else if (CurMethodDef) { - FuncName = CurMethodDef->getSelector().getAsString(); - // Convert colons to underscores. - std::string::size_type loc = 0; - while ((loc = FuncName.find(":", loc)) != std::string::npos) - FuncName.replace(loc, 1, "_"); - } else if (VD) - FuncName = std::string(VD->getNameAsString()); - - std::string BlockNumber = utostr(Blocks.size()-1); - - std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; - std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; - - std::string FunkTypeStr; - - // Get a pointer to the function type so we can cast appropriately. - Context->getPointerType(QualType(Exp->getFunctionType(),0)) - .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy); - - // Rewrite the closure block with a compound literal. The first cast is - // to prevent warnings from the C compiler. - std::string Init = "(" + FunkTypeStr; - - Init += ")&" + Tag; - - // Initialize the block function. - Init += "((void*)" + Func; - - if (ImportedBlockDecls.size()) { - std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber; - Init += ",(void*)" + Buf; - Buf = "__" + FuncName + "_block_dispose_" + BlockNumber; - Init += ",(void*)" + Buf; - } - // Add initializers for any closure decl refs. - if (BlockDeclRefs.size()) { - // Output all "by copy" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - Init += ","; - if (isObjCType((*I)->getType())) { - Init += "[["; - Init += (*I)->getNameAsString(); - Init += " retain] autorelease]"; - } else if (isBlockPointerType((*I)->getType())) { - Init += "(void *)"; - Init += (*I)->getNameAsString(); - } else { - Init += (*I)->getNameAsString(); - } - } - // Output all "by ref" declarations. - for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - Init += ",&"; - Init += (*I)->getNameAsString(); - } - } - Init += ")"; - BlockDeclRefs.clear(); - BlockByRefDecls.clear(); - BlockByCopyDecls.clear(); - ImportedBlockDecls.clear(); - - return Init; -} - -//===----------------------------------------------------------------------===// -// Function Body / Expression rewriting -//===----------------------------------------------------------------------===// - -Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) { - // Start by rewriting all children. - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) { - RewriteFunctionBody(CBE->getBody()); - - // We've just rewritten the block body in place. - // Now we snarf the rewritten text and stash it away for later use. - std::string S = Rewrite.getRewritenText(CBE->getSourceRange()); - RewrittenBlockExprs[CBE] = S; - std::string Init = SynthesizeBlockInitExpr(CBE); - // Do the rewrite, using S.size() which contains the rewritten size. - ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size()); - } else { - RewriteFunctionBody(*CI); - } - } - // Handle specific things. - if (CallExpr *CE = dyn_cast<CallExpr>(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) - RewriteBlockCall(CE); - } - if (CastExpr *CE = dyn_cast<CastExpr>(S)) { - RewriteCastExpr(CE); - } - if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { - for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); - DI != DE; ++DI) { - - Decl *SD = *DI; - if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) { - if (isBlockPointerType(ND->getType())) - RewriteBlockPointerDecl(ND); - else if (ND->getType()->isFunctionPointerType()) - CheckFunctionPointerDecl(ND->getType(), ND); - } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { - if (isBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - } - } - } - // Handle specific things. - if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { - if (BDRE->isByRef()) - RewriteBlockDeclRefExpr(BDRE); - } - // Return this stmt unmodified. - return S; -} - -void RewriteBlocks::RewriteFunctionProtoType(QualType funcType, NamedDecl *D) { - if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) { - for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), - E = fproto->arg_type_end(); I && (I != E); ++I) - if (isBlockPointerType(*I)) { - // All the args are checked/rewritten. Don't call twice! - RewriteBlockPointerDecl(D); - break; - } - } -} - -void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { - const PointerType *PT = funcType->getAs<PointerType>(); - if (PT && PointerTypeTakesAnyBlockArguments(funcType)) - RewriteFunctionProtoType(PT->getPointeeType(), ND); -} - -/// HandleDeclInMainFile - This is called for each top-level decl defined in the -/// main file of the input. -void RewriteBlocks::HandleDeclInMainFile(Decl *D) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Since function prototypes don't have ParmDecl's, we check the function - // prototype. This enables us to rewrite function declarations and - // definitions using the same code. - RewriteFunctionProtoType(FD->getType(), FD); - - // FIXME: Handle CXXTryStmt - if (CompoundStmt *Body = FD->getCompoundBody()) { - CurFunctionDef = FD; - FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body))); - // This synthesizes and inserts the block "impl" struct, invoke function, - // and any copy/dispose helper functions. - InsertBlockLiteralsWithinFunction(FD); - CurFunctionDef = 0; - } - return; - } - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - RewriteMethodDecl(MD); - if (Stmt *Body = MD->getBody()) { - CurMethodDef = MD; - RewriteFunctionBody(Body); - InsertBlockLiteralsWithinMethod(MD); - CurMethodDef = 0; - } - } - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (isBlockPointerType(VD->getType())) { - RewriteBlockPointerDecl(VD); - if (VD->getInit()) { - if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) { - RewriteFunctionBody(CBE->getBody()); - - // We've just rewritten the block body in place. - // Now we snarf the rewritten text and stash it away for later use. - std::string S = Rewrite.getRewritenText(CBE->getSourceRange()); - RewrittenBlockExprs[CBE] = S; - std::string Init = SynthesizeBlockInitExpr(CBE, VD); - // Do the rewrite, using S.size() which contains the rewritten size. - ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size()); - SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), - VD->getNameAsCString()); - } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } else if (VD->getType()->isFunctionPointerType()) { - CheckFunctionPointerDecl(VD->getType(), VD); - if (VD->getInit()) { - if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) { - RewriteCastExpr(CE); - } - } - } - return; - } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { - if (isBlockPointerType(TD->getUnderlyingType())) - RewriteBlockPointerDecl(TD); - else if (TD->getUnderlyingType()->isFunctionPointerType()) - CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - return; - } - if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { - if (RD->isDefinition()) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - } - } - return; - } -} diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index df85c13..c347472 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -30,6 +30,28 @@ using llvm::utostr; namespace { class RewriteObjC : public ASTConsumer { + enum { + BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), + block, ... */ + BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ + BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the + __block variable */ + BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy + helpers */ + BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose + support routines */ + BLOCK_BYREF_CURRENT_MAX = 256 + }; + + enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) + }; + Rewriter Rewrite; Diagnostic &Diags; const LangOptions &LangOpts; @@ -324,6 +346,7 @@ namespace { // Block specific rewrite rules. void RewriteBlockCall(CallExpr *Exp); void RewriteBlockPointerDecl(NamedDecl *VD); + void RewriteByRefVar(VarDecl *VD); Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD); void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); @@ -337,7 +360,7 @@ namespace { std::string ImplTag, int i, const char *funcName, unsigned hasCopy); - Stmt *SynthesizeBlockCall(CallExpr *Exp); + Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName); void RewriteRecordBody(RecordDecl *RD); @@ -565,8 +588,8 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; Preamble += "#else\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_dispose(const void *, const int);\n"; Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; Preamble += "#endif\n"; @@ -576,6 +599,8 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; Preamble += "#define __attribute__(X)\n"; } + else + Preamble += "#define __block\n"; } @@ -3731,8 +3756,8 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); - Context->getPointerType((*I)->getType()).getAsStringInternal(Name, - Context->PrintingPolicy); + std::string TypeString = "struct __Block_byref_" + Name + " *"; + Name = TypeString + Name; S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; } // Next, emit a declaration for all "by copy" declarations. @@ -3781,8 +3806,13 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, S += (*I)->getNameAsString(); S += ", (void*)src->"; S += (*I)->getNameAsString(); - S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);}"; + if (BlockByRefDecls.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; } + S += "}\n"; + S += "\nstatic void __"; S += funcName; S += "_block_dispose_" + utostr(i); @@ -3792,7 +3822,10 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, E = ImportedBlockDecls.end(); I != E; ++I) { S += "_Block_object_dispose((void*)src->"; S += (*I)->getNameAsString(); - S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);"; + if (BlockByRefDecls.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; } S += "}\n"; return S; @@ -3858,10 +3891,10 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += "struct __block_impl *"; Constructor += ", void *" + ArgName; } else { - Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName, - Context->PrintingPolicy); - Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName, - Context->PrintingPolicy); + std::string TypeString = "struct __Block_byref_" + FieldName; + TypeString += " *"; + FieldName = TypeString + FieldName; + ArgName = TypeString + ArgName; Constructor += ", " + ArgName; } S += FieldName + "; // by ref\n"; @@ -3896,7 +3929,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += Name + " = (struct __block_impl *)_"; else Constructor += Name + " = _"; - Constructor += Name + ";\n"; + Constructor += Name + "->__forwarding;\n"; } } else { // Finish writing the constructor. @@ -3924,7 +3957,12 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, S += " {\n unsigned long reserved;\n"; S += " unsigned long Block_size;\n"; if (hasCopy) { - S += " void *copy;\n void *dispose;\n"; + S += " void (*copy)(struct "; + S += ImplTag; S += "*, struct "; + S += ImplTag; S += "*);\n"; + + S += " void (*dispose)(struct "; + S += ImplTag; S += "*);\n"; } S += "} "; @@ -4030,20 +4068,38 @@ void RewriteObjC::GetBlockCallExprs(Stmt *S) { return; } -Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { +Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { // Navigate to relevant type information. - const char *closureName = 0; const BlockPointerType *CPT = 0; - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) { - closureName = DRE->getDecl()->getNameAsCString(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) { CPT = DRE->getType()->getAs<BlockPointerType>(); - } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) { - closureName = CDRE->getDecl()->getNameAsCString(); + } else if (const BlockDeclRefExpr *CDRE = + dyn_cast<BlockDeclRefExpr>(BlockExp)) { CPT = CDRE->getType()->getAs<BlockPointerType>(); - } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) { - closureName = MExpr->getMemberDecl()->getNameAsCString(); + } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) { CPT = MExpr->getType()->getAs<BlockPointerType>(); + } + else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) { + return SynthesizeBlockCall(Exp, PRE->getSubExpr()); + } + else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp)) + CPT = IEXPR->getType()->getAs<BlockPointerType>(); + else if (const ConditionalOperator *CEXPR = + dyn_cast<ConditionalOperator>(BlockExp)) { + Expr *LHSExp = CEXPR->getLHS(); + Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); + Expr *RHSExp = CEXPR->getRHS(); + Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); + Expr *CONDExp = CEXPR->getCond(); + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(CONDExp, + SourceLocation(), cast<Expr>(LHSStmt), + SourceLocation(), cast<Expr>(RHSStmt), + Exp->getType()); + return CondExpr; + } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) { + CPT = IRE->getType()->getAs<BlockPointerType>(); } else { assert(1 && "RewriteBlockClass: Bad type"); } @@ -4083,7 +4139,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock, CastExpr::CK_Unknown, - Exp->getCallee(), + const_cast<Expr*>(BlockExp), PtrBlock, SourceLocation(), SourceLocation()); // Don't forget the parens to enforce the proper binding. @@ -4119,7 +4175,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { } void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { - Stmt *BlockCall = SynthesizeBlockCall(Exp); + Stmt *BlockCall = SynthesizeBlockCall(Exp, Exp->getCallee()); ReplaceStmt(Exp, BlockCall); } @@ -4137,12 +4193,27 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { // }; //} Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) { - // FIXME: Add more elaborate code generation required by the ABI. - Expr *DerefExpr = new (Context) UnaryOperator(BDRE, UnaryOperator::Deref, - Context->getPointerType(BDRE->getType()), - SourceLocation()); + // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR + // for each BDRE where BYREFVAR is name of the variable. + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get("__forwarding"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + MemberExpr *ME = new (Context) MemberExpr(BDRE, true, FD, SourceLocation(), + FD->getType()); + const char *Name = BDRE->getDecl()->getNameAsCString(); + FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get(Name), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), + BDRE->getType()); + + + // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), DerefExpr); + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + ME); ReplaceStmt(BDRE, PE); return PE; } @@ -4298,6 +4369,94 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { return; } +/// RewriteByRefVar - For each __block typex ND variable this routine transforms +/// the declaration into: +/// struct __Block_byref_ND { +/// void *__isa; // NULL for everything except __weak pointers +/// struct __Block_byref_ND *__forwarding; +/// int32_t __flags; +/// int32_t __size; +/// void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object +/// void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object +/// typex ND; +/// }; +/// +/// It then replaces declaration of ND variable with: +/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, +/// __size=sizeof(struct __Block_byref_ND), +/// ND=initializer-if-any}; +/// +/// +void RewriteObjC::RewriteByRefVar(VarDecl *ND) { + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + const char *startBuf = SM->getCharacterData(DeclLoc); + SourceLocation X = ND->getLocEnd(); + X = SM->getInstantiationLoc(X); + const char *endBuf = SM->getCharacterData(X); + std::string Name(ND->getNameAsString()); + std::string ByrefType = "struct __Block_byref_"; + ByrefType += Name; + ByrefType += " {\n"; + ByrefType += " void *__isa;\n"; + ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n"; + ByrefType += " int __flags;\n"; + ByrefType += " int __size;\n"; + // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr; + // if needed. + ND->getType().getAsStringInternal(Name, Context->PrintingPolicy); + ByrefType += " " + Name + ";\n"; + ByrefType += "};\n"; + // Insert this type in global scope. It is needed by helper function. + assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null"); + SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size()); + + // struct __Block_byref_ND ND = + // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), + // initializer-if-any}; + bool hasInit = (ND->getInit() != 0); + Name = ND->getNameAsString(); + ByrefType = "struct __Block_byref_" + Name; + if (!hasInit) { + ByrefType += " " + Name + " = "; + ByrefType += "{0, &" + Name + ", "; + // FIXME. Compute the flag. + ByrefType += "0, "; + ByrefType += "sizeof(struct __Block_byref_" + Name + ")"; + ByrefType += "};\n"; + ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), + ByrefType.c_str(), ByrefType.size()); + } + else { + SourceLocation startLoc = ND->getInit()->getLocStart(); + ByrefType += " " + Name; + ReplaceText(DeclLoc, endBuf-startBuf, + ByrefType.c_str(), ByrefType.size()); + ByrefType = " = {0, &" + Name + ", "; + // FIXME. Compute the flag. + ByrefType += "0, "; + ByrefType += "sizeof(struct __Block_byref_" + Name + "), "; + InsertText(startLoc, ByrefType.c_str(), ByrefType.size()); + + // Complete the newly synthesized compound expression by inserting a right + // curly brace before the end of the declaration. + // FIXME: This approach avoids rewriting the initializer expression. It + // also assumes there is only one declarator. For example, the following + // isn't currently supported by this routine (in general): + // + // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; + // + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); + SourceLocation semiLoc = + startLoc.getFileLocWithOffset(semiBuf-startBuf); + + InsertText(semiLoc, "}", 1); + } + return; +} + void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { // Add initializers for any closure decl refs. GetBlockDeclRefExprs(Exp->getBody()); @@ -4313,7 +4472,9 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { } // Find any imported blocks...they will need special attention. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getType()->isBlockPointerType()) { + if (BlockDeclRefs[i]->isByRef() || + BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + BlockDeclRefs[i]->getType()->isBlockPointerType()) { GetBlockCallExprs(BlockDeclRefs[i]); ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); } @@ -4422,16 +4583,14 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { InitExprs.push_back(Exp); } } - if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions. + if (ImportedBlockDecls.size()) { + // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR + int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); unsigned IntSize = static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); - BinaryOperator *Exp = new (Context) BinaryOperator( - new (Context) IntegerLiteral(llvm::APInt(IntSize, 1), - Context->IntTy,SourceLocation()), - new (Context) IntegerLiteral(llvm::APInt(IntSize, 25), - Context->IntTy, SourceLocation()), - BinaryOperator::Shl, Context->IntTy, SourceLocation()); - InitExprs.push_back(Exp); + Expr *FlagExp = new (Context) IntegerLiteral(llvm::APInt(IntSize, flag), + Context->IntTy, SourceLocation()); + InitExprs.push_back(FlagExp); } NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), FType, SourceLocation()); @@ -4479,7 +4638,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { Stmts.push_back(S); else if (isa<ObjCForCollectionStmt>(S)) { Stmts.push_back(S); - ObjCBcLabelNo.push_back(++BcLabelCount); + ++BcLabelCount; + ObjCBcLabelNo.push_back(BcLabelCount); } SourceRange OrigStmtRange = S->getSourceRange(); @@ -4640,6 +4800,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { RewriteBlockPointerDecl(ND); else if (ND->getType()->isFunctionPointerType()) CheckFunctionPointerDecl(ND->getType(), ND); + if (VarDecl *VD = dyn_cast<VarDecl>(SD)) + if (VD->hasAttr<BlocksAttr>()) + RewriteByRefVar(VD); } if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (isTopLevelBlockPointerType(TD->getUnderlyingType())) @@ -4668,7 +4831,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { } if (CallExpr *CE = dyn_cast<CallExpr>(S)) { if (CE->getCallee()->getType()->isBlockPointerType()) { - Stmt *BlockCall = SynthesizeBlockCall(CE); + Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); ReplaceStmt(S, BlockCall); return BlockCall; } diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index ff44c90..4bf507d 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -13,12 +13,12 @@ // // This file is responsible for handling all warning options. This includes // a number of -Wfoo options and their variants, which are driven by TableGen- -// generated data, and the special cases -pedantic, -pedantic-errors, -w and -// -Werror. +// generated data, and the special cases -pedantic, -pedantic-errors, -w, +// -Werror and -Wfatal-errors. // // Each warning option controls any number of actual warnings. // Given a warning option 'foo', the following are valid: -// -Wfoo, -Wno-foo, -Werror=foo +// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo // #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" @@ -26,7 +26,6 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" -#include <cstdio> #include <cstring> #include <utility> #include <algorithm> @@ -47,8 +46,6 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, else Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); - // FIXME: -Wfatal-errors / -Wfatal-errors=foo - for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { const std::string &Opt = Opts.Warnings[i]; const char *OptStart = &Opt[0]; @@ -81,8 +78,8 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, if (OptEnd-OptStart != 5) { // Specifier must be present. if ((OptStart[5] != '=' && OptStart[5] != '-') || OptEnd-OptStart == 6) { - fprintf(stderr, "warning: unknown -Werror warning specifier: -W%s\n", - Opt.c_str()); + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Werror" << ("-W" + Opt); continue; } Specifier = OptStart+6; @@ -98,6 +95,30 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, OptStart = Specifier; } + // -Wfatal-errors is yet another special case. + if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) { + const char* Specifier = 0; + if (OptEnd-OptStart != 12) { + if ((OptStart[12] != '=' && OptStart[12] != '-') || + OptEnd-OptStart == 13) { + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Wfatal-errors" << ("-W" + Opt); + continue; + } + Specifier = OptStart + 13; + } + + if (Specifier == 0) { + Diags.setErrorsAsFatal(isPositive); + continue; + } + + // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo + // maps it to Error. + Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL; + OptStart = Specifier; + } + if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); } |