From 7a51313d8a0a358bb92eb5dbf8fd846b7c48e7fe Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 15 Mar 2008 23:59:48 +0000 Subject: Make a major restructuring of the clang tree: introduce a top-level lib dir and move all the libraries into it. This follows the main llvm tree, and allows the libraries to be built in parallel. The top level now enforces that all the libs are built before Driver, but we don't care what order the libs are built in. This speeds up parallel builds, particularly incremental ones. llvm-svn: 48402 --- clang/AST/ASTConsumer.cpp | 28 - clang/AST/ASTContext.cpp | 1853 ---------------------- clang/AST/Builtins.cpp | 195 --- clang/AST/CFG.cpp | 1509 ------------------ clang/AST/Decl.cpp | 652 -------- clang/AST/DeclSerialization.cpp | 463 ------ clang/AST/Expr.cpp | 1391 ----------------- clang/AST/ExprCXX.cpp | 47 - clang/AST/Makefile | 22 - clang/AST/Stmt.cpp | 293 ---- clang/AST/StmtDumper.cpp | 486 ------ clang/AST/StmtIterator.cpp | 118 -- clang/AST/StmtPrinter.cpp | 854 ----------- clang/AST/StmtSerialization.cpp | 1001 ------------ clang/AST/StmtViz.cpp | 59 - clang/AST/TranslationUnit.cpp | 225 --- clang/AST/Type.cpp | 978 ------------ clang/AST/TypeSerialization.cpp | 293 ---- clang/Analysis/BasicValueFactory.cpp | 167 -- clang/Analysis/CFRefCount.cpp | 796 ---------- clang/Analysis/DeadStores.cpp | 87 -- clang/Analysis/ExplodedGraph.cpp | 227 --- clang/Analysis/GRBlockCounter.cpp | 54 - clang/Analysis/GRCoreEngine.cpp | 444 ------ clang/Analysis/GRExprEngine.cpp | 1941 ----------------------- clang/Analysis/GRSimpleVals.cpp | 462 ------ clang/Analysis/GRSimpleVals.h | 71 - clang/Analysis/LiveVariables.cpp | 246 --- clang/Analysis/Makefile | 22 - clang/Analysis/ProgramPoint.cpp | 65 - clang/Analysis/RValues.cpp | 389 ----- clang/Analysis/SymbolManager.cpp | 124 -- clang/Analysis/UninitializedValues.cpp | 277 ---- clang/Analysis/ValueState.cpp | 595 ------- clang/Basic/Diagnostic.cpp | 232 --- clang/Basic/FileManager.cpp | 275 ---- clang/Basic/IdentifierTable.cpp | 551 ------- clang/Basic/LangOptions.cpp | 58 - clang/Basic/Makefile | 22 - clang/Basic/SourceLocation.cpp | 79 - clang/Basic/SourceManager.cpp | 574 ------- clang/Basic/TargetInfo.cpp | 210 --- clang/Basic/Targets.cpp | 757 --------- clang/Basic/TokenKinds.cpp | 29 - clang/CodeGen/CGBuiltin.cpp | 486 ------ clang/CodeGen/CGDecl.cpp | 163 -- clang/CodeGen/CGExpr.cpp | 615 -------- clang/CodeGen/CGExprAgg.cpp | 337 ---- clang/CodeGen/CGExprComplex.cpp | 542 ------- clang/CodeGen/CGExprConstant.cpp | 627 -------- clang/CodeGen/CGExprScalar.cpp | 1185 -------------- clang/CodeGen/CGObjC.cpp | 25 - clang/CodeGen/CGObjCGNU.cpp | 97 -- clang/CodeGen/CGObjCRuntime.h | 47 - clang/CodeGen/CGStmt.cpp | 776 ---------- clang/CodeGen/CodeGenFunction.cpp | 182 --- clang/CodeGen/CodeGenFunction.h | 486 ------ clang/CodeGen/CodeGenModule.cpp | 509 ------ clang/CodeGen/CodeGenModule.h | 129 -- clang/CodeGen/CodeGenTypes.cpp | 580 ------- clang/CodeGen/CodeGenTypes.h | 165 -- clang/CodeGen/Makefile | 23 - clang/CodeGen/ModuleBuilder.cpp | 104 -- clang/Headers/Makefile | 39 - clang/Headers/mmintrin.devel.h | 377 ----- clang/Headers/stdbool.h | 38 - clang/Lex/HeaderMap.cpp | 242 --- clang/Lex/HeaderSearch.cpp | 425 ----- clang/Lex/Lexer.cpp | 1661 -------------------- clang/Lex/LiteralSupport.cpp | 691 --------- clang/Lex/MacroArgs.cpp | 225 --- clang/Lex/MacroArgs.h | 109 -- clang/Lex/MacroInfo.cpp | 70 - clang/Lex/Makefile | 28 - clang/Lex/PPDirectives.cpp | 1153 -------------- clang/Lex/PPExpressions.cpp | 639 -------- clang/Lex/PPLexerChange.cpp | 401 ----- clang/Lex/PPMacroExpansion.cpp | 523 ------- clang/Lex/Pragma.cpp | 386 ----- clang/Lex/Preprocessor.cpp | 560 ------- clang/Lex/ScratchBuffer.cpp | 72 - clang/Lex/TokenLexer.cpp | 488 ------ clang/Makefile | 2 +- clang/Parse/AttributeList.cpp | 98 -- clang/Parse/DeclSpec.cpp | 287 ---- clang/Parse/Makefile | 22 - clang/Parse/MinimalAction.cpp | 136 -- clang/Parse/ParseDecl.cpp | 1540 ------------------- clang/Parse/ParseDeclCXX.cpp | 119 -- clang/Parse/ParseExpr.cpp | 1081 ------------- clang/Parse/ParseExprCXX.cpp | 99 -- clang/Parse/ParseInit.cpp | 227 --- clang/Parse/ParseObjc.cpp | 1578 ------------------- clang/Parse/ParseStmt.cpp | 1159 -------------- clang/Parse/Parser.cpp | 647 -------- clang/Rewrite/Makefile | 22 - clang/Rewrite/Rewriter.cpp | 258 ---- clang/Sema/Makefile | 23 - clang/Sema/ParseAST.cpp | 69 - clang/Sema/Sema.cpp | 222 --- clang/Sema/Sema.h | 823 ---------- clang/Sema/SemaChecking.cpp | 802 ---------- clang/Sema/SemaDecl.cpp | 2297 ---------------------------- clang/Sema/SemaDeclObjC.cpp | 927 ----------- clang/Sema/SemaExpr.cpp | 2286 --------------------------- clang/Sema/SemaExprCXX.cpp | 51 - clang/Sema/SemaExprObjC.cpp | 297 ---- clang/Sema/SemaStmt.cpp | 821 ---------- clang/Sema/SemaType.cpp | 498 ------ clang/Sema/SemaUtil.h | 35 - clang/clang.xcodeproj/project.pbxproj | 160 +- clang/lib/AST/ASTConsumer.cpp | 28 + clang/lib/AST/ASTContext.cpp | 1853 ++++++++++++++++++++++ clang/lib/AST/Builtins.cpp | 195 +++ clang/lib/AST/CFG.cpp | 1509 ++++++++++++++++++ clang/lib/AST/Decl.cpp | 652 ++++++++ clang/lib/AST/DeclSerialization.cpp | 463 ++++++ clang/lib/AST/Expr.cpp | 1391 +++++++++++++++++ clang/lib/AST/ExprCXX.cpp | 47 + clang/lib/AST/Makefile | 22 + clang/lib/AST/Stmt.cpp | 293 ++++ clang/lib/AST/StmtDumper.cpp | 486 ++++++ clang/lib/AST/StmtIterator.cpp | 118 ++ clang/lib/AST/StmtPrinter.cpp | 854 +++++++++++ clang/lib/AST/StmtSerialization.cpp | 1001 ++++++++++++ clang/lib/AST/StmtViz.cpp | 59 + clang/lib/AST/TranslationUnit.cpp | 225 +++ clang/lib/AST/Type.cpp | 978 ++++++++++++ clang/lib/AST/TypeSerialization.cpp | 293 ++++ clang/lib/Analysis/BasicValueFactory.cpp | 167 ++ clang/lib/Analysis/CFRefCount.cpp | 796 ++++++++++ clang/lib/Analysis/DeadStores.cpp | 87 ++ clang/lib/Analysis/ExplodedGraph.cpp | 227 +++ clang/lib/Analysis/GRBlockCounter.cpp | 54 + clang/lib/Analysis/GRCoreEngine.cpp | 444 ++++++ clang/lib/Analysis/GRExprEngine.cpp | 1941 +++++++++++++++++++++++ clang/lib/Analysis/GRSimpleVals.cpp | 462 ++++++ clang/lib/Analysis/GRSimpleVals.h | 71 + clang/lib/Analysis/LiveVariables.cpp | 246 +++ clang/lib/Analysis/Makefile | 22 + clang/lib/Analysis/ProgramPoint.cpp | 65 + clang/lib/Analysis/RValues.cpp | 389 +++++ clang/lib/Analysis/SymbolManager.cpp | 124 ++ clang/lib/Analysis/UninitializedValues.cpp | 277 ++++ clang/lib/Analysis/ValueState.cpp | 595 +++++++ clang/lib/Basic/Diagnostic.cpp | 232 +++ clang/lib/Basic/FileManager.cpp | 275 ++++ clang/lib/Basic/IdentifierTable.cpp | 551 +++++++ clang/lib/Basic/LangOptions.cpp | 58 + clang/lib/Basic/Makefile | 22 + clang/lib/Basic/SourceLocation.cpp | 79 + clang/lib/Basic/SourceManager.cpp | 574 +++++++ clang/lib/Basic/TargetInfo.cpp | 210 +++ clang/lib/Basic/Targets.cpp | 757 +++++++++ clang/lib/Basic/TokenKinds.cpp | 29 + clang/lib/CodeGen/CGBuiltin.cpp | 486 ++++++ clang/lib/CodeGen/CGDecl.cpp | 163 ++ clang/lib/CodeGen/CGExpr.cpp | 615 ++++++++ clang/lib/CodeGen/CGExprAgg.cpp | 337 ++++ clang/lib/CodeGen/CGExprComplex.cpp | 542 +++++++ clang/lib/CodeGen/CGExprConstant.cpp | 627 ++++++++ clang/lib/CodeGen/CGExprScalar.cpp | 1185 ++++++++++++++ clang/lib/CodeGen/CGObjC.cpp | 25 + clang/lib/CodeGen/CGObjCGNU.cpp | 97 ++ clang/lib/CodeGen/CGObjCRuntime.h | 47 + clang/lib/CodeGen/CGStmt.cpp | 776 ++++++++++ clang/lib/CodeGen/CodeGenFunction.cpp | 182 +++ clang/lib/CodeGen/CodeGenFunction.h | 486 ++++++ clang/lib/CodeGen/CodeGenModule.cpp | 509 ++++++ clang/lib/CodeGen/CodeGenModule.h | 129 ++ clang/lib/CodeGen/CodeGenTypes.cpp | 580 +++++++ clang/lib/CodeGen/CodeGenTypes.h | 165 ++ clang/lib/CodeGen/Makefile | 23 + clang/lib/CodeGen/ModuleBuilder.cpp | 104 ++ clang/lib/Headers/Makefile | 39 + clang/lib/Headers/mmintrin.devel.h | 377 +++++ clang/lib/Headers/stdbool.h | 38 + clang/lib/Lex/HeaderMap.cpp | 242 +++ clang/lib/Lex/HeaderSearch.cpp | 425 +++++ clang/lib/Lex/Lexer.cpp | 1661 ++++++++++++++++++++ clang/lib/Lex/LiteralSupport.cpp | 691 +++++++++ clang/lib/Lex/MacroArgs.cpp | 225 +++ clang/lib/Lex/MacroArgs.h | 109 ++ clang/lib/Lex/MacroInfo.cpp | 70 + clang/lib/Lex/Makefile | 28 + clang/lib/Lex/PPDirectives.cpp | 1153 ++++++++++++++ clang/lib/Lex/PPExpressions.cpp | 639 ++++++++ clang/lib/Lex/PPLexerChange.cpp | 401 +++++ clang/lib/Lex/PPMacroExpansion.cpp | 523 +++++++ clang/lib/Lex/Pragma.cpp | 386 +++++ clang/lib/Lex/Preprocessor.cpp | 560 +++++++ clang/lib/Lex/ScratchBuffer.cpp | 72 + clang/lib/Lex/TokenLexer.cpp | 488 ++++++ clang/lib/Makefile | 14 + clang/lib/Parse/AttributeList.cpp | 98 ++ clang/lib/Parse/DeclSpec.cpp | 287 ++++ clang/lib/Parse/Makefile | 22 + clang/lib/Parse/MinimalAction.cpp | 136 ++ clang/lib/Parse/ParseDecl.cpp | 1540 +++++++++++++++++++ clang/lib/Parse/ParseDeclCXX.cpp | 119 ++ clang/lib/Parse/ParseExpr.cpp | 1081 +++++++++++++ clang/lib/Parse/ParseExprCXX.cpp | 99 ++ clang/lib/Parse/ParseInit.cpp | 227 +++ clang/lib/Parse/ParseObjc.cpp | 1578 +++++++++++++++++++ clang/lib/Parse/ParseStmt.cpp | 1159 ++++++++++++++ clang/lib/Parse/Parser.cpp | 647 ++++++++ clang/lib/Rewrite/Makefile | 22 + clang/lib/Rewrite/Rewriter.cpp | 258 ++++ clang/lib/Sema/Makefile | 23 + clang/lib/Sema/ParseAST.cpp | 69 + clang/lib/Sema/Sema.cpp | 222 +++ clang/lib/Sema/Sema.h | 823 ++++++++++ clang/lib/Sema/SemaChecking.cpp | 802 ++++++++++ clang/lib/Sema/SemaDecl.cpp | 2297 ++++++++++++++++++++++++++++ clang/lib/Sema/SemaDeclObjC.cpp | 927 +++++++++++ clang/lib/Sema/SemaExpr.cpp | 2286 +++++++++++++++++++++++++++ clang/lib/Sema/SemaExprCXX.cpp | 51 + clang/lib/Sema/SemaExprObjC.cpp | 297 ++++ clang/lib/Sema/SemaStmt.cpp | 821 ++++++++++ clang/lib/Sema/SemaType.cpp | 498 ++++++ clang/lib/Sema/SemaUtil.h | 35 + 221 files changed, 50945 insertions(+), 50931 deletions(-) delete mode 100644 clang/AST/ASTConsumer.cpp delete mode 100644 clang/AST/ASTContext.cpp delete mode 100644 clang/AST/Builtins.cpp delete mode 100644 clang/AST/CFG.cpp delete mode 100644 clang/AST/Decl.cpp delete mode 100644 clang/AST/DeclSerialization.cpp delete mode 100644 clang/AST/Expr.cpp delete mode 100644 clang/AST/ExprCXX.cpp delete mode 100644 clang/AST/Makefile delete mode 100644 clang/AST/Stmt.cpp delete mode 100644 clang/AST/StmtDumper.cpp delete mode 100644 clang/AST/StmtIterator.cpp delete mode 100644 clang/AST/StmtPrinter.cpp delete mode 100644 clang/AST/StmtSerialization.cpp delete mode 100644 clang/AST/StmtViz.cpp delete mode 100644 clang/AST/TranslationUnit.cpp delete mode 100644 clang/AST/Type.cpp delete mode 100644 clang/AST/TypeSerialization.cpp delete mode 100644 clang/Analysis/BasicValueFactory.cpp delete mode 100644 clang/Analysis/CFRefCount.cpp delete mode 100644 clang/Analysis/DeadStores.cpp delete mode 100644 clang/Analysis/ExplodedGraph.cpp delete mode 100644 clang/Analysis/GRBlockCounter.cpp delete mode 100644 clang/Analysis/GRCoreEngine.cpp delete mode 100644 clang/Analysis/GRExprEngine.cpp delete mode 100644 clang/Analysis/GRSimpleVals.cpp delete mode 100644 clang/Analysis/GRSimpleVals.h delete mode 100644 clang/Analysis/LiveVariables.cpp delete mode 100644 clang/Analysis/Makefile delete mode 100644 clang/Analysis/ProgramPoint.cpp delete mode 100644 clang/Analysis/RValues.cpp delete mode 100644 clang/Analysis/SymbolManager.cpp delete mode 100644 clang/Analysis/UninitializedValues.cpp delete mode 100644 clang/Analysis/ValueState.cpp delete mode 100644 clang/Basic/Diagnostic.cpp delete mode 100644 clang/Basic/FileManager.cpp delete mode 100644 clang/Basic/IdentifierTable.cpp delete mode 100644 clang/Basic/LangOptions.cpp delete mode 100644 clang/Basic/Makefile delete mode 100644 clang/Basic/SourceLocation.cpp delete mode 100644 clang/Basic/SourceManager.cpp delete mode 100644 clang/Basic/TargetInfo.cpp delete mode 100644 clang/Basic/Targets.cpp delete mode 100644 clang/Basic/TokenKinds.cpp delete mode 100644 clang/CodeGen/CGBuiltin.cpp delete mode 100644 clang/CodeGen/CGDecl.cpp delete mode 100644 clang/CodeGen/CGExpr.cpp delete mode 100644 clang/CodeGen/CGExprAgg.cpp delete mode 100644 clang/CodeGen/CGExprComplex.cpp delete mode 100644 clang/CodeGen/CGExprConstant.cpp delete mode 100644 clang/CodeGen/CGExprScalar.cpp delete mode 100644 clang/CodeGen/CGObjC.cpp delete mode 100644 clang/CodeGen/CGObjCGNU.cpp delete mode 100644 clang/CodeGen/CGObjCRuntime.h delete mode 100644 clang/CodeGen/CGStmt.cpp delete mode 100644 clang/CodeGen/CodeGenFunction.cpp delete mode 100644 clang/CodeGen/CodeGenFunction.h delete mode 100644 clang/CodeGen/CodeGenModule.cpp delete mode 100644 clang/CodeGen/CodeGenModule.h delete mode 100644 clang/CodeGen/CodeGenTypes.cpp delete mode 100644 clang/CodeGen/CodeGenTypes.h delete mode 100644 clang/CodeGen/Makefile delete mode 100644 clang/CodeGen/ModuleBuilder.cpp delete mode 100644 clang/Headers/Makefile delete mode 100644 clang/Headers/mmintrin.devel.h delete mode 100644 clang/Headers/stdbool.h delete mode 100644 clang/Lex/HeaderMap.cpp delete mode 100644 clang/Lex/HeaderSearch.cpp delete mode 100644 clang/Lex/Lexer.cpp delete mode 100644 clang/Lex/LiteralSupport.cpp delete mode 100644 clang/Lex/MacroArgs.cpp delete mode 100644 clang/Lex/MacroArgs.h delete mode 100644 clang/Lex/MacroInfo.cpp delete mode 100644 clang/Lex/Makefile delete mode 100644 clang/Lex/PPDirectives.cpp delete mode 100644 clang/Lex/PPExpressions.cpp delete mode 100644 clang/Lex/PPLexerChange.cpp delete mode 100644 clang/Lex/PPMacroExpansion.cpp delete mode 100644 clang/Lex/Pragma.cpp delete mode 100644 clang/Lex/Preprocessor.cpp delete mode 100644 clang/Lex/ScratchBuffer.cpp delete mode 100644 clang/Lex/TokenLexer.cpp delete mode 100644 clang/Parse/AttributeList.cpp delete mode 100644 clang/Parse/DeclSpec.cpp delete mode 100644 clang/Parse/Makefile delete mode 100644 clang/Parse/MinimalAction.cpp delete mode 100644 clang/Parse/ParseDecl.cpp delete mode 100644 clang/Parse/ParseDeclCXX.cpp delete mode 100644 clang/Parse/ParseExpr.cpp delete mode 100644 clang/Parse/ParseExprCXX.cpp delete mode 100644 clang/Parse/ParseInit.cpp delete mode 100644 clang/Parse/ParseObjc.cpp delete mode 100644 clang/Parse/ParseStmt.cpp delete mode 100644 clang/Parse/Parser.cpp delete mode 100644 clang/Rewrite/Makefile delete mode 100644 clang/Rewrite/Rewriter.cpp delete mode 100644 clang/Sema/Makefile delete mode 100644 clang/Sema/ParseAST.cpp delete mode 100644 clang/Sema/Sema.cpp delete mode 100644 clang/Sema/Sema.h delete mode 100644 clang/Sema/SemaChecking.cpp delete mode 100644 clang/Sema/SemaDecl.cpp delete mode 100644 clang/Sema/SemaDeclObjC.cpp delete mode 100644 clang/Sema/SemaExpr.cpp delete mode 100644 clang/Sema/SemaExprCXX.cpp delete mode 100644 clang/Sema/SemaExprObjC.cpp delete mode 100644 clang/Sema/SemaStmt.cpp delete mode 100644 clang/Sema/SemaType.cpp delete mode 100644 clang/Sema/SemaUtil.h create mode 100644 clang/lib/AST/ASTConsumer.cpp create mode 100644 clang/lib/AST/ASTContext.cpp create mode 100644 clang/lib/AST/Builtins.cpp create mode 100644 clang/lib/AST/CFG.cpp create mode 100644 clang/lib/AST/Decl.cpp create mode 100644 clang/lib/AST/DeclSerialization.cpp create mode 100644 clang/lib/AST/Expr.cpp create mode 100644 clang/lib/AST/ExprCXX.cpp create mode 100644 clang/lib/AST/Makefile create mode 100644 clang/lib/AST/Stmt.cpp create mode 100644 clang/lib/AST/StmtDumper.cpp create mode 100644 clang/lib/AST/StmtIterator.cpp create mode 100644 clang/lib/AST/StmtPrinter.cpp create mode 100644 clang/lib/AST/StmtSerialization.cpp create mode 100644 clang/lib/AST/StmtViz.cpp create mode 100644 clang/lib/AST/TranslationUnit.cpp create mode 100644 clang/lib/AST/Type.cpp create mode 100644 clang/lib/AST/TypeSerialization.cpp create mode 100644 clang/lib/Analysis/BasicValueFactory.cpp create mode 100644 clang/lib/Analysis/CFRefCount.cpp create mode 100644 clang/lib/Analysis/DeadStores.cpp create mode 100644 clang/lib/Analysis/ExplodedGraph.cpp create mode 100644 clang/lib/Analysis/GRBlockCounter.cpp create mode 100644 clang/lib/Analysis/GRCoreEngine.cpp create mode 100644 clang/lib/Analysis/GRExprEngine.cpp create mode 100644 clang/lib/Analysis/GRSimpleVals.cpp create mode 100644 clang/lib/Analysis/GRSimpleVals.h create mode 100644 clang/lib/Analysis/LiveVariables.cpp create mode 100644 clang/lib/Analysis/Makefile create mode 100644 clang/lib/Analysis/ProgramPoint.cpp create mode 100644 clang/lib/Analysis/RValues.cpp create mode 100644 clang/lib/Analysis/SymbolManager.cpp create mode 100644 clang/lib/Analysis/UninitializedValues.cpp create mode 100644 clang/lib/Analysis/ValueState.cpp create mode 100644 clang/lib/Basic/Diagnostic.cpp create mode 100644 clang/lib/Basic/FileManager.cpp create mode 100644 clang/lib/Basic/IdentifierTable.cpp create mode 100644 clang/lib/Basic/LangOptions.cpp create mode 100644 clang/lib/Basic/Makefile create mode 100644 clang/lib/Basic/SourceLocation.cpp create mode 100644 clang/lib/Basic/SourceManager.cpp create mode 100644 clang/lib/Basic/TargetInfo.cpp create mode 100644 clang/lib/Basic/Targets.cpp create mode 100644 clang/lib/Basic/TokenKinds.cpp create mode 100644 clang/lib/CodeGen/CGBuiltin.cpp create mode 100644 clang/lib/CodeGen/CGDecl.cpp create mode 100644 clang/lib/CodeGen/CGExpr.cpp create mode 100644 clang/lib/CodeGen/CGExprAgg.cpp create mode 100644 clang/lib/CodeGen/CGExprComplex.cpp create mode 100644 clang/lib/CodeGen/CGExprConstant.cpp create mode 100644 clang/lib/CodeGen/CGExprScalar.cpp create mode 100644 clang/lib/CodeGen/CGObjC.cpp create mode 100644 clang/lib/CodeGen/CGObjCGNU.cpp create mode 100644 clang/lib/CodeGen/CGObjCRuntime.h create mode 100644 clang/lib/CodeGen/CGStmt.cpp create mode 100644 clang/lib/CodeGen/CodeGenFunction.cpp create mode 100644 clang/lib/CodeGen/CodeGenFunction.h create mode 100644 clang/lib/CodeGen/CodeGenModule.cpp create mode 100644 clang/lib/CodeGen/CodeGenModule.h create mode 100644 clang/lib/CodeGen/CodeGenTypes.cpp create mode 100644 clang/lib/CodeGen/CodeGenTypes.h create mode 100644 clang/lib/CodeGen/Makefile create mode 100644 clang/lib/CodeGen/ModuleBuilder.cpp create mode 100644 clang/lib/Headers/Makefile create mode 100644 clang/lib/Headers/mmintrin.devel.h create mode 100644 clang/lib/Headers/stdbool.h create mode 100644 clang/lib/Lex/HeaderMap.cpp create mode 100644 clang/lib/Lex/HeaderSearch.cpp create mode 100644 clang/lib/Lex/Lexer.cpp create mode 100644 clang/lib/Lex/LiteralSupport.cpp create mode 100644 clang/lib/Lex/MacroArgs.cpp create mode 100644 clang/lib/Lex/MacroArgs.h create mode 100644 clang/lib/Lex/MacroInfo.cpp create mode 100644 clang/lib/Lex/Makefile create mode 100644 clang/lib/Lex/PPDirectives.cpp create mode 100644 clang/lib/Lex/PPExpressions.cpp create mode 100644 clang/lib/Lex/PPLexerChange.cpp create mode 100644 clang/lib/Lex/PPMacroExpansion.cpp create mode 100644 clang/lib/Lex/Pragma.cpp create mode 100644 clang/lib/Lex/Preprocessor.cpp create mode 100644 clang/lib/Lex/ScratchBuffer.cpp create mode 100644 clang/lib/Lex/TokenLexer.cpp create mode 100755 clang/lib/Makefile create mode 100644 clang/lib/Parse/AttributeList.cpp create mode 100644 clang/lib/Parse/DeclSpec.cpp create mode 100644 clang/lib/Parse/Makefile create mode 100644 clang/lib/Parse/MinimalAction.cpp create mode 100644 clang/lib/Parse/ParseDecl.cpp create mode 100644 clang/lib/Parse/ParseDeclCXX.cpp create mode 100644 clang/lib/Parse/ParseExpr.cpp create mode 100644 clang/lib/Parse/ParseExprCXX.cpp create mode 100644 clang/lib/Parse/ParseInit.cpp create mode 100644 clang/lib/Parse/ParseObjc.cpp create mode 100644 clang/lib/Parse/ParseStmt.cpp create mode 100644 clang/lib/Parse/Parser.cpp create mode 100644 clang/lib/Rewrite/Makefile create mode 100644 clang/lib/Rewrite/Rewriter.cpp create mode 100644 clang/lib/Sema/Makefile create mode 100644 clang/lib/Sema/ParseAST.cpp create mode 100644 clang/lib/Sema/Sema.cpp create mode 100644 clang/lib/Sema/Sema.h create mode 100644 clang/lib/Sema/SemaChecking.cpp create mode 100644 clang/lib/Sema/SemaDecl.cpp create mode 100644 clang/lib/Sema/SemaDeclObjC.cpp create mode 100644 clang/lib/Sema/SemaExpr.cpp create mode 100644 clang/lib/Sema/SemaExprCXX.cpp create mode 100644 clang/lib/Sema/SemaExprObjC.cpp create mode 100644 clang/lib/Sema/SemaStmt.cpp create mode 100644 clang/lib/Sema/SemaType.cpp create mode 100644 clang/lib/Sema/SemaUtil.h (limited to 'clang') diff --git a/clang/AST/ASTConsumer.cpp b/clang/AST/ASTConsumer.cpp deleted file mode 100644 index b3d12710927..00000000000 --- a/clang/AST/ASTConsumer.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- 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 ASTConsumer class. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/Decl.h" -using namespace clang; - -ASTConsumer::~ASTConsumer() {} - -void ASTConsumer::HandleTopLevelDeclaration(Decl* d) { - if (ScopedDecl* sd = dyn_cast(d)) - while (sd) { - HandleTopLevelDecl(sd); - sd = sd->getNextDeclarator(); - } - else - HandleTopLevelDecl(d); -} diff --git a/clang/AST/ASTContext.cpp b/clang/AST/ASTContext.cpp deleted file mode 100644 index db4d53aa481..00000000000 --- a/clang/AST/ASTContext.cpp +++ /dev/null @@ -1,1853 +0,0 @@ -//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the ASTContext interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using namespace clang; - -enum FloatingRank { - FloatRank, DoubleRank, LongDoubleRank -}; - -ASTContext::~ASTContext() { - // Deallocate all the types. - while (!Types.empty()) { - if (FunctionTypeProto *FT = dyn_cast(Types.back())) { - // Destroy the object, but don't call delete. These are malloc'd. - FT->~FunctionTypeProto(); - free(FT); - } else { - delete Types.back(); - } - Types.pop_back(); - } -} - -void ASTContext::PrintStats() const { - fprintf(stderr, "*** AST Context Stats:\n"); - fprintf(stderr, " %d types total.\n", (int)Types.size()); - unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0; - unsigned NumVector = 0, NumComplex = 0; - unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0; - - unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0; - unsigned NumObjCInterfaces = 0, NumObjCQualifiedInterfaces = 0; - unsigned NumObjCQualifiedIds = 0; - - for (unsigned i = 0, e = Types.size(); i != e; ++i) { - Type *T = Types[i]; - if (isa(T)) - ++NumBuiltin; - else if (isa(T)) - ++NumPointer; - else if (isa(T)) - ++NumReference; - else if (isa(T)) - ++NumComplex; - else if (isa(T)) - ++NumArray; - else if (isa(T)) - ++NumVector; - else if (isa(T)) - ++NumFunctionNP; - else if (isa(T)) - ++NumFunctionP; - else if (isa(T)) - ++NumTypeName; - else if (TagType *TT = dyn_cast(T)) { - ++NumTagged; - switch (TT->getDecl()->getKind()) { - default: assert(0 && "Unknown tagged type!"); - case Decl::Struct: ++NumTagStruct; break; - case Decl::Union: ++NumTagUnion; break; - case Decl::Class: ++NumTagClass; break; - case Decl::Enum: ++NumTagEnum; break; - } - } else if (isa(T)) - ++NumObjCInterfaces; - else if (isa(T)) - ++NumObjCQualifiedInterfaces; - else if (isa(T)) - ++NumObjCQualifiedIds; - else { - QualType(T, 0).dump(); - assert(0 && "Unknown type!"); - } - } - - fprintf(stderr, " %d builtin types\n", NumBuiltin); - fprintf(stderr, " %d pointer types\n", NumPointer); - fprintf(stderr, " %d reference types\n", NumReference); - fprintf(stderr, " %d complex types\n", NumComplex); - fprintf(stderr, " %d array types\n", NumArray); - fprintf(stderr, " %d vector types\n", NumVector); - fprintf(stderr, " %d function types with proto\n", NumFunctionP); - fprintf(stderr, " %d function types with no proto\n", NumFunctionNP); - fprintf(stderr, " %d typename (typedef) types\n", NumTypeName); - fprintf(stderr, " %d tagged types\n", NumTagged); - fprintf(stderr, " %d struct types\n", NumTagStruct); - fprintf(stderr, " %d union types\n", NumTagUnion); - fprintf(stderr, " %d class types\n", NumTagClass); - fprintf(stderr, " %d enum types\n", NumTagEnum); - fprintf(stderr, " %d interface types\n", NumObjCInterfaces); - fprintf(stderr, " %d protocol qualified interface types\n", - NumObjCQualifiedInterfaces); - fprintf(stderr, " %d protocol qualified id types\n", - NumObjCQualifiedIds); - fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+ - NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+ - NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+ - NumFunctionP*sizeof(FunctionTypeProto)+ - NumFunctionNP*sizeof(FunctionTypeNoProto)+ - NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType))); -} - - -void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { - Types.push_back((R = QualType(new BuiltinType(K),0)).getTypePtr()); -} - -void ASTContext::InitBuiltinTypes() { - assert(VoidTy.isNull() && "Context reinitialized?"); - - // C99 6.2.5p19. - InitBuiltinType(VoidTy, BuiltinType::Void); - - // C99 6.2.5p2. - InitBuiltinType(BoolTy, BuiltinType::Bool); - // C99 6.2.5p3. - if (Target.isCharSigned()) - InitBuiltinType(CharTy, BuiltinType::Char_S); - else - InitBuiltinType(CharTy, BuiltinType::Char_U); - // C99 6.2.5p4. - InitBuiltinType(SignedCharTy, BuiltinType::SChar); - InitBuiltinType(ShortTy, BuiltinType::Short); - InitBuiltinType(IntTy, BuiltinType::Int); - InitBuiltinType(LongTy, BuiltinType::Long); - InitBuiltinType(LongLongTy, BuiltinType::LongLong); - - // C99 6.2.5p6. - InitBuiltinType(UnsignedCharTy, BuiltinType::UChar); - InitBuiltinType(UnsignedShortTy, BuiltinType::UShort); - InitBuiltinType(UnsignedIntTy, BuiltinType::UInt); - InitBuiltinType(UnsignedLongTy, BuiltinType::ULong); - InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong); - - // C99 6.2.5p10. - InitBuiltinType(FloatTy, BuiltinType::Float); - InitBuiltinType(DoubleTy, BuiltinType::Double); - InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble); - - // C99 6.2.5p11. - FloatComplexTy = getComplexType(FloatTy); - DoubleComplexTy = getComplexType(DoubleTy); - LongDoubleComplexTy = getComplexType(LongDoubleTy); - - BuiltinVaListType = QualType(); - ObjCIdType = QualType(); - IdStructType = 0; - ObjCClassType = QualType(); - ClassStructType = 0; - - ObjCConstantStringType = QualType(); - - // void * type - VoidPtrTy = getPointerType(VoidTy); -} - -//===----------------------------------------------------------------------===// -// Type Sizing and Analysis -//===----------------------------------------------------------------------===// - -/// getTypeSize - Return the size of the specified type, in bits. This method -/// does not work on incomplete types. -std::pair -ASTContext::getTypeInfo(QualType T) { - T = T.getCanonicalType(); - uint64_t Width; - unsigned Align; - switch (T->getTypeClass()) { - case Type::TypeName: assert(0 && "Not a canonical type!"); - case Type::FunctionNoProto: - case Type::FunctionProto: - default: - assert(0 && "Incomplete types have no size!"); - case Type::VariableArray: - assert(0 && "VLAs not implemented yet!"); - case Type::ConstantArray: { - ConstantArrayType *CAT = cast(T); - - std::pair EltInfo = getTypeInfo(CAT->getElementType()); - Width = EltInfo.first*CAT->getSize().getZExtValue(); - Align = EltInfo.second; - break; - } - case Type::OCUVector: - case Type::Vector: { - std::pair EltInfo = - getTypeInfo(cast(T)->getElementType()); - Width = EltInfo.first*cast(T)->getNumElements(); - // FIXME: Vector alignment is not the alignment of its elements. - Align = EltInfo.second; - break; - } - - case Type::Builtin: - // FIXME: need to use TargetInfo to derive the target specific sizes. This - // implementation will suffice for play with vector support. - switch (cast(T)->getKind()) { - default: assert(0 && "Unknown builtin type!"); - case BuiltinType::Void: - assert(0 && "Incomplete types have no size!"); - case BuiltinType::Bool: - Width = Target.getBoolWidth(); - Align = Target.getBoolAlign(); - break; - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::SChar: - Width = Target.getCharWidth(); - Align = Target.getCharAlign(); - break; - case BuiltinType::UShort: - case BuiltinType::Short: - Width = Target.getShortWidth(); - Align = Target.getShortAlign(); - break; - case BuiltinType::UInt: - case BuiltinType::Int: - Width = Target.getIntWidth(); - Align = Target.getIntAlign(); - break; - case BuiltinType::ULong: - case BuiltinType::Long: - Width = Target.getLongWidth(); - Align = Target.getLongAlign(); - break; - case BuiltinType::ULongLong: - case BuiltinType::LongLong: - Width = Target.getLongLongWidth(); - Align = Target.getLongLongAlign(); - break; - case BuiltinType::Float: - Width = Target.getFloatWidth(); - Align = Target.getFloatAlign(); - break; - case BuiltinType::Double: - Width = Target.getDoubleWidth(); - Align = Target.getDoubleAlign(); - break; - case BuiltinType::LongDouble: - Width = Target.getLongDoubleWidth(); - Align = Target.getLongDoubleAlign(); - break; - } - break; - case Type::ASQual: - // FIXME: Pointers into different addr spaces could have different sizes and - // alignment requirements: getPointerInfo should take an AddrSpace. - return getTypeInfo(QualType(cast(T)->getBaseType(), 0)); - case Type::ObjCQualifiedId: - Width = Target.getPointerWidth(0); - Align = Target.getPointerAlign(0); - break; - case Type::Pointer: { - unsigned AS = cast(T)->getPointeeType().getAddressSpace(); - Width = Target.getPointerWidth(AS); - Align = Target.getPointerAlign(AS); - break; - } - case Type::Reference: - // "When applied to a reference or a reference type, the result is the size - // of the referenced type." C++98 5.3.3p2: expr.sizeof. - // FIXME: This is wrong for struct layout: a reference in a struct has - // pointer size. - return getTypeInfo(cast(T)->getReferenceeType()); - - case Type::Complex: { - // Complex types have the same alignment as their elements, but twice the - // size. - std::pair EltInfo = - getTypeInfo(cast(T)->getElementType()); - Width = EltInfo.first*2; - Align = EltInfo.second; - break; - } - case Type::Tagged: - TagType *TT = cast(T); - if (RecordType *RT = dyn_cast(TT)) { - const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); - Width = Layout.getSize(); - Align = Layout.getAlignment(); - } else if (EnumDecl *ED = dyn_cast(TT->getDecl())) { - return getTypeInfo(ED->getIntegerType()); - } else { - assert(0 && "Unimplemented type sizes!"); - } - break; - } - - assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); - return std::make_pair(Width, Align); -} - -/// getASTRecordLayout - Get or compute information about the layout of the -/// specified record (struct/union/class), which indicates its size and field -/// position information. -const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { - assert(D->isDefinition() && "Cannot get layout of forward declarations!"); - - // Look up this layout, if already laid out, return what we have. - const ASTRecordLayout *&Entry = ASTRecordLayouts[D]; - if (Entry) return *Entry; - - // Allocate and assign into ASTRecordLayouts here. The "Entry" reference can - // be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into. - ASTRecordLayout *NewEntry = new ASTRecordLayout(); - Entry = NewEntry; - - uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()]; - uint64_t RecordSize = 0; - unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits. - - if (D->getKind() != Decl::Union) { - if (const AlignedAttr *AA = D->getAttr()) - RecordAlign = std::max(RecordAlign, AA->getAlignment()); - - bool StructIsPacked = D->getAttr(); - - // Layout each field, for now, just sequentially, respecting alignment. In - // the future, this will need to be tweakable by targets. - for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { - const FieldDecl *FD = D->getMember(i); - bool FieldIsPacked = StructIsPacked || FD->getAttr(); - uint64_t FieldSize; - unsigned FieldAlign; - - if (const Expr *BitWidthExpr = FD->getBitWidth()) { - llvm::APSInt I(32); - bool BitWidthIsICE = - BitWidthExpr->isIntegerConstantExpr(I, *this); - assert (BitWidthIsICE && "Invalid BitField size expression"); - FieldSize = I.getZExtValue(); - - std::pair TypeInfo = getTypeInfo(FD->getType()); - uint64_t TypeSize = TypeInfo.first; - - if (const AlignedAttr *AA = FD->getAttr()) - FieldAlign = AA->getAlignment(); - else if (FieldIsPacked) - FieldAlign = 8; - else { - // FIXME: This is X86 specific, use 32-bit alignment for long long. - if (FD->getType()->isIntegerType() && TypeInfo.second > 32) - FieldAlign = 32; - else - FieldAlign = TypeInfo.second; - } - - // Check if we need to add padding to give the field the correct - // alignment. - if (RecordSize % FieldAlign + FieldSize > TypeSize) - RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); - - } else { - if (FD->getType()->isIncompleteType()) { - // This must be 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. - - if (const AlignedAttr *AA = FD->getAttr()) - FieldAlign = AA->getAlignment(); - else if (FieldIsPacked) - FieldAlign = 8; - else { - const ArrayType* ATy = FD->getType()->getAsArrayType(); - FieldAlign = getTypeAlign(ATy->getElementType()); - } - FieldSize = 0; - } else { - std::pair FieldInfo = getTypeInfo(FD->getType()); - FieldSize = FieldInfo.first; - - if (const AlignedAttr *AA = FD->getAttr()) - FieldAlign = AA->getAlignment(); - else if (FieldIsPacked) - FieldAlign = 8; - else - FieldAlign = FieldInfo.second; - } - - // Round up the current record size to the field's alignment boundary. - RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); - } - - // Place this field at the current location. - FieldOffsets[i] = RecordSize; - - // Reserve space for this field. - RecordSize += FieldSize; - - // Remember max struct/class alignment. - RecordAlign = std::max(RecordAlign, FieldAlign); - } - - // Finally, round the size of the total struct up to the alignment of the - // struct itself. - RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1); - } else { - // Union layout just puts each member at the start of the record. - for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { - const FieldDecl *FD = D->getMember(i); - std::pair FieldInfo = getTypeInfo(FD->getType()); - uint64_t FieldSize = FieldInfo.first; - unsigned FieldAlign = FieldInfo.second; - - // FIXME: This is X86 specific, use 32-bit alignment for long long. - if (FD->getType()->isIntegerType() && FieldAlign > 32) - FieldAlign = 32; - - // Round up the current record size to the field's alignment boundary. - RecordSize = std::max(RecordSize, FieldSize); - - // Place this field at the start of the record. - FieldOffsets[i] = 0; - - // Remember max struct/class alignment. - RecordAlign = std::max(RecordAlign, FieldAlign); - } - } - - NewEntry->SetLayout(RecordSize, RecordAlign, FieldOffsets); - return *NewEntry; -} - -//===----------------------------------------------------------------------===// -// Type creation/memoization methods -//===----------------------------------------------------------------------===// - -QualType ASTContext::getASQualType(QualType T, unsigned AddressSpace) { - if (T.getCanonicalType().getAddressSpace() == AddressSpace) - return T; - - // Type's cannot have multiple ASQuals, therefore we know we only have to deal - // with CVR qualifiers from here on out. - assert(T.getCanonicalType().getAddressSpace() == 0 && - "Type is already address space qualified"); - - // Check if we've already instantiated an address space qual'd type of this - // type. - llvm::FoldingSetNodeID ID; - ASQualType::Profile(ID, T.getTypePtr(), AddressSpace); - void *InsertPos = 0; - if (ASQualType *ASQy = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(ASQy, 0); - - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getASQualType(T.getCanonicalType(), AddressSpace); - - // Get the new insert position for the node we care about. - ASQualType *NewIP = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - ASQualType *New = new ASQualType(T.getTypePtr(), Canonical, AddressSpace); - ASQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, T.getCVRQualifiers()); -} - - -/// getComplexType - Return the uniqued reference to the type for a complex -/// number with the specified element type. -QualType ASTContext::getComplexType(QualType T) { - // Unique pointers, to guarantee there is only one pointer of a particular - // structure. - llvm::FoldingSetNodeID ID; - ComplexType::Profile(ID, T); - - void *InsertPos = 0; - if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(CT, 0); - - // If the pointee type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getComplexType(T.getCanonicalType()); - - // Get the new insert position for the node we care about. - ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - ComplexType *New = new ComplexType(T, Canonical); - Types.push_back(New); - ComplexTypes.InsertNode(New, InsertPos); - return QualType(New, 0); -} - - -/// getPointerType - Return the uniqued reference to the type for a pointer to -/// the specified type. -QualType ASTContext::getPointerType(QualType T) { - // Unique pointers, to guarantee there is only one pointer of a particular - // structure. - llvm::FoldingSetNodeID ID; - PointerType::Profile(ID, T); - - void *InsertPos = 0; - if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(PT, 0); - - // If the pointee type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getPointerType(T.getCanonicalType()); - - // Get the new insert position for the node we care about. - PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - PointerType *New = new PointerType(T, Canonical); - Types.push_back(New); - PointerTypes.InsertNode(New, InsertPos); - return QualType(New, 0); -} - -/// getReferenceType - Return the uniqued reference to the type for a reference -/// to the specified type. -QualType ASTContext::getReferenceType(QualType T) { - // Unique pointers, to guarantee there is only one pointer of a particular - // structure. - llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T); - - void *InsertPos = 0; - if (ReferenceType *RT = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(RT, 0); - - // If the referencee type isn't canonical, this won't be a canonical type - // either, so fill in the canonical type field. - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getReferenceType(T.getCanonicalType()); - - // Get the new insert position for the node we care about. - ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - - ReferenceType *New = new ReferenceType(T, Canonical); - Types.push_back(New); - ReferenceTypes.InsertNode(New, InsertPos); - return QualType(New, 0); -} - -/// getConstantArrayType - Return the unique reference to the type for an -/// array of the specified element type. -QualType ASTContext::getConstantArrayType(QualType EltTy, - const llvm::APInt &ArySize, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - llvm::FoldingSetNodeID ID; - ConstantArrayType::Profile(ID, EltTy, ArySize); - - void *InsertPos = 0; - if (ConstantArrayType *ATP = - ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(ATP, 0); - - // If the element type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!EltTy->isCanonical()) { - Canonical = getConstantArrayType(EltTy.getCanonicalType(), ArySize, - ASM, EltTypeQuals); - // Get the new insert position for the node we care about. - ConstantArrayType *NewIP = - ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - - ConstantArrayType *New = new ConstantArrayType(EltTy, Canonical, ArySize, - ASM, EltTypeQuals); - ConstantArrayTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); -} - -/// getVariableArrayType - Returns a non-unique reference to the type for a -/// variable array of the specified element type. -QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - // Since we don't unique expressions, it isn't possible to unique VLA's - // that have an expression provided for their size. - - VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts, - ASM, EltTypeQuals); - - VariableArrayTypes.push_back(New); - Types.push_back(New); - return QualType(New, 0); -} - -QualType ASTContext::getIncompleteArrayType(QualType EltTy, - ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - llvm::FoldingSetNodeID ID; - IncompleteArrayType::Profile(ID, EltTy); - - void *InsertPos = 0; - if (IncompleteArrayType *ATP = - IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(ATP, 0); - - // If the element type isn't canonical, this won't be a canonical type - // either, so fill in the canonical type field. - QualType Canonical; - - if (!EltTy->isCanonical()) { - Canonical = getIncompleteArrayType(EltTy.getCanonicalType(), - ASM, EltTypeQuals); - - // Get the new insert position for the node we care about. - IncompleteArrayType *NewIP = - IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - - IncompleteArrayType *New = new IncompleteArrayType(EltTy, Canonical, - ASM, EltTypeQuals); - - IncompleteArrayTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); -} - -/// getVectorType - Return the unique reference to a vector type of -/// the specified element type and size. VectorType must be a built-in type. -QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { - BuiltinType *baseType; - - baseType = dyn_cast(vecType.getCanonicalType().getTypePtr()); - assert(baseType != 0 && "getVectorType(): Expecting a built-in type"); - - // Check if we've already instantiated a vector of this type. - llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::Vector); - void *InsertPos = 0; - if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(VTP, 0); - - // If the element type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!vecType->isCanonical()) { - Canonical = getVectorType(vecType.getCanonicalType(), NumElts); - - // Get the new insert position for the node we care about. - VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - VectorType *New = new VectorType(vecType, NumElts, Canonical); - VectorTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); -} - -/// getOCUVectorType - Return the unique reference to an OCU vector type of -/// the specified element type and size. VectorType must be a built-in type. -QualType ASTContext::getOCUVectorType(QualType vecType, unsigned NumElts) { - BuiltinType *baseType; - - baseType = dyn_cast(vecType.getCanonicalType().getTypePtr()); - assert(baseType != 0 && "getOCUVectorType(): Expecting a built-in type"); - - // Check if we've already instantiated a vector of this type. - llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::OCUVector); - void *InsertPos = 0; - if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(VTP, 0); - - // If the element type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!vecType->isCanonical()) { - Canonical = getOCUVectorType(vecType.getCanonicalType(), NumElts); - - // Get the new insert position for the node we care about. - VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - OCUVectorType *New = new OCUVectorType(vecType, NumElts, Canonical); - VectorTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); -} - -/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'. -/// -QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) { - // Unique functions, to guarantee there is only one function of a particular - // structure. - llvm::FoldingSetNodeID ID; - FunctionTypeNoProto::Profile(ID, ResultTy); - - void *InsertPos = 0; - if (FunctionTypeNoProto *FT = - FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(FT, 0); - - QualType Canonical; - if (!ResultTy->isCanonical()) { - Canonical = getFunctionTypeNoProto(ResultTy.getCanonicalType()); - - // Get the new insert position for the node we care about. - FunctionTypeNoProto *NewIP = - FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - - FunctionTypeNoProto *New = new FunctionTypeNoProto(ResultTy, Canonical); - Types.push_back(New); - FunctionTypeNoProtos.InsertNode(New, InsertPos); - return QualType(New, 0); -} - -/// getFunctionType - Return a normal function type with a typed argument -/// list. isVariadic indicates whether the argument list includes '...'. -QualType ASTContext::getFunctionType(QualType ResultTy, QualType *ArgArray, - unsigned NumArgs, bool isVariadic) { - // Unique functions, to guarantee there is only one function of a particular - // structure. - llvm::FoldingSetNodeID ID; - FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic); - - void *InsertPos = 0; - if (FunctionTypeProto *FTP = - FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(FTP, 0); - - // Determine whether the type being created is already canonical or not. - bool isCanonical = ResultTy->isCanonical(); - for (unsigned i = 0; i != NumArgs && isCanonical; ++i) - if (!ArgArray[i]->isCanonical()) - isCanonical = false; - - // If this type isn't canonical, get the canonical version of it. - QualType Canonical; - if (!isCanonical) { - llvm::SmallVector CanonicalArgs; - CanonicalArgs.reserve(NumArgs); - for (unsigned i = 0; i != NumArgs; ++i) - CanonicalArgs.push_back(ArgArray[i].getCanonicalType()); - - Canonical = getFunctionType(ResultTy.getCanonicalType(), - &CanonicalArgs[0], NumArgs, - isVariadic); - - // Get the new insert position for the node we care about. - FunctionTypeProto *NewIP = - FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - - // FunctionTypeProto objects are not allocated with new because they have a - // variable size array (for parameter types) at the end of them. - FunctionTypeProto *FTP = - (FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) + - NumArgs*sizeof(QualType)); - new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic, - Canonical); - Types.push_back(FTP); - FunctionTypeProtos.InsertNode(FTP, InsertPos); - return QualType(FTP, 0); -} - -/// getTypedefType - Return the unique reference to the type for the -/// specified typename decl. -QualType ASTContext::getTypedefType(TypedefDecl *Decl) { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - QualType Canonical = Decl->getUnderlyingType().getCanonicalType(); - Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); -} - -/// getObjCInterfaceType - Return the unique reference to the type for the -/// specified ObjC interface decl. -QualType ASTContext::getObjCInterfaceType(ObjCInterfaceDecl *Decl) { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - Decl->TypeForDecl = new ObjCInterfaceType(Type::ObjCInterface, Decl); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); -} - -/// getObjCQualifiedInterfaceType - Return a -/// ObjCQualifiedInterfaceType type for the given interface decl and -/// the conforming protocol list. -QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - llvm::FoldingSetNodeID ID; - ObjCQualifiedInterfaceType::Profile(ID, Protocols, NumProtocols); - - void *InsertPos = 0; - if (ObjCQualifiedInterfaceType *QT = - ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(QT, 0); - - // No Match; - ObjCQualifiedInterfaceType *QType = - new ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols); - Types.push_back(QType); - ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos); - return QualType(QType, 0); -} - -/// getObjCQualifiedIdType - Return a -/// getObjCQualifiedIdType type for the 'id' decl and -/// the conforming protocol list. -QualType ASTContext::getObjCQualifiedIdType(QualType idType, - ObjCProtocolDecl **Protocols, - unsigned NumProtocols) { - llvm::FoldingSetNodeID ID; - ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols); - - void *InsertPos = 0; - if (ObjCQualifiedIdType *QT = - ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(QT, 0); - - // No Match; - QualType Canonical; - if (!idType->isCanonical()) { - Canonical = getObjCQualifiedIdType(idType.getCanonicalType(), - Protocols, NumProtocols); - ObjCQualifiedIdType *NewQT = - ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewQT == 0 && "Shouldn't be in the map!"); - } - - ObjCQualifiedIdType *QType = - new ObjCQualifiedIdType(Canonical, Protocols, NumProtocols); - Types.push_back(QType); - ObjCQualifiedIdTypes.InsertNode(QType, InsertPos); - return QualType(QType, 0); -} - -/// getTypeOfExpr - Unlike many "get" functions, we can't unique -/// TypeOfExpr AST's (since expression's are never shared). For example, -/// multiple declarations that refer to "typeof(x)" all contain different -/// DeclRefExpr's. This doesn't effect the type checker, since it operates -/// on canonical type's (which are always unique). -QualType ASTContext::getTypeOfExpr(Expr *tofExpr) { - QualType Canonical = tofExpr->getType().getCanonicalType(); - TypeOfExpr *toe = new TypeOfExpr(tofExpr, Canonical); - Types.push_back(toe); - return QualType(toe, 0); -} - -/// getTypeOfType - Unlike many "get" functions, we don't unique -/// TypeOfType AST's. The only motivation to unique these nodes would be -/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be -/// an issue. This doesn't effect the type checker, since it operates -/// on canonical type's (which are always unique). -QualType ASTContext::getTypeOfType(QualType tofType) { - QualType Canonical = tofType.getCanonicalType(); - TypeOfType *tot = new TypeOfType(tofType, Canonical); - Types.push_back(tot); - return QualType(tot, 0); -} - -/// getTagDeclType - Return the unique reference to the type for the -/// specified TagDecl (struct/union/class/enum) decl. -QualType ASTContext::getTagDeclType(TagDecl *Decl) { - assert (Decl); - - // The decl stores the type cache. - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - TagType* T = new TagType(Decl, QualType()); - Types.push_back(T); - Decl->TypeForDecl = T; - - return QualType(T, 0); -} - -/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result -/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and -/// needs to agree with the definition in . -QualType ASTContext::getSizeType() const { - // On Darwin, size_t is defined as a "long unsigned int". - // FIXME: should derive from "Target". - return UnsignedLongTy; -} - -/// getWcharType - Return the unique type for "wchar_t" (C99 7.17), the -/// width of characters in wide strings, The value is target dependent and -/// needs to agree with the definition in . -QualType ASTContext::getWcharType() const { - // On Darwin, wchar_t is defined as a "int". - // FIXME: should derive from "Target". - return IntTy; -} - -/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) -/// defined in . Pointer - pointer requires this (C99 6.5.6p9). -QualType ASTContext::getPointerDiffType() const { - // On Darwin, ptrdiff_t is defined as a "int". This seems like a bug... - // FIXME: should derive from "Target". - return IntTy; -} - -/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This -/// routine will assert if passed a built-in type that isn't an integer or enum. -static int getIntegerRank(QualType t) { - if (const TagType *TT = dyn_cast(t.getCanonicalType())) { - assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum"); - return 4; - } - - const BuiltinType *BT = t.getCanonicalType()->getAsBuiltinType(); - switch (BT->getKind()) { - default: - assert(0 && "getIntegerRank(): not a built-in integer"); - case BuiltinType::Bool: - return 1; - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - return 2; - case BuiltinType::Short: - case BuiltinType::UShort: - return 3; - case BuiltinType::Int: - case BuiltinType::UInt: - return 4; - case BuiltinType::Long: - case BuiltinType::ULong: - return 5; - case BuiltinType::LongLong: - case BuiltinType::ULongLong: - return 6; - } -} - -/// getFloatingRank - Return a relative rank for floating point types. -/// This routine will assert if passed a built-in type that isn't a float. -static int getFloatingRank(QualType T) { - T = T.getCanonicalType(); - if (const ComplexType *CT = T->getAsComplexType()) - return getFloatingRank(CT->getElementType()); - - switch (T->getAsBuiltinType()->getKind()) { - default: assert(0 && "getFloatingRank(): not a floating type"); - case BuiltinType::Float: return FloatRank; - case BuiltinType::Double: return DoubleRank; - case BuiltinType::LongDouble: return LongDoubleRank; - } -} - -/// getFloatingTypeOfSizeWithinDomain - Returns a real floating -/// point or a complex type (based on typeDomain/typeSize). -/// 'typeDomain' is a real floating point or complex type. -/// 'typeSize' is a real floating point or complex type. -QualType ASTContext::getFloatingTypeOfSizeWithinDomain( - QualType typeSize, QualType typeDomain) const { - if (typeDomain->isComplexType()) { - switch (getFloatingRank(typeSize)) { - default: assert(0 && "getFloatingRank(): illegal value for rank"); - case FloatRank: return FloatComplexTy; - case DoubleRank: return DoubleComplexTy; - case LongDoubleRank: return LongDoubleComplexTy; - } - } - if (typeDomain->isRealFloatingType()) { - switch (getFloatingRank(typeSize)) { - default: assert(0 && "getFloatingRank(): illegal value for rank"); - case FloatRank: return FloatTy; - case DoubleRank: return DoubleTy; - case LongDoubleRank: return LongDoubleTy; - } - } - assert(0 && "getFloatingTypeOfSizeWithinDomain(): illegal domain"); - //an invalid return value, but the assert - //will ensure that this code is never reached. - return VoidTy; -} - -/// compareFloatingType - Handles 3 different combos: -/// float/float, float/complex, complex/complex. -/// If lt > rt, return 1. If lt == rt, return 0. If lt < rt, return -1. -int ASTContext::compareFloatingType(QualType lt, QualType rt) { - if (getFloatingRank(lt) == getFloatingRank(rt)) - return 0; - if (getFloatingRank(lt) > getFloatingRank(rt)) - return 1; - return -1; -} - -// maxIntegerType - Returns the highest ranked integer type. Handles 3 case: -// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1. -QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) { - if (lhs == rhs) return lhs; - - bool t1Unsigned = lhs->isUnsignedIntegerType(); - bool t2Unsigned = rhs->isUnsignedIntegerType(); - - if ((t1Unsigned && t2Unsigned) || (!t1Unsigned && !t2Unsigned)) - return getIntegerRank(lhs) >= getIntegerRank(rhs) ? lhs : rhs; - - // We have two integer types with differing signs - QualType unsignedType = t1Unsigned ? lhs : rhs; - QualType signedType = t1Unsigned ? rhs : lhs; - - if (getIntegerRank(unsignedType) >= getIntegerRank(signedType)) - return unsignedType; - else { - // FIXME: Need to check if the signed type can represent all values of the - // unsigned type. If it can, then the result is the signed type. - // If it can't, then the result is the unsigned version of the signed type. - // Should probably add a helper that returns a signed integer type from - // an unsigned (and vice versa). C99 6.3.1.8. - return signedType; - } -} - -// getCFConstantStringType - Return the type used for constant CFStrings. -QualType ASTContext::getCFConstantStringType() { - if (!CFConstantStringTypeDecl) { - CFConstantStringTypeDecl = - RecordDecl::Create(*this, Decl::Struct, SourceLocation(), - &Idents.get("NSConstantString"), 0); - QualType FieldTypes[4]; - - // const int *isa; - FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); - // int flags; - FieldTypes[1] = IntTy; - // const char *str; - FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); - // long length; - FieldTypes[3] = LongTy; - // Create fields - FieldDecl *FieldDecls[4]; - - for (unsigned i = 0; i < 4; ++i) - FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]); - - CFConstantStringTypeDecl->defineBody(FieldDecls, 4); - } - - return getTagDeclType(CFConstantStringTypeDecl); -} - -// This returns true if a type has been typedefed to BOOL: -// typedef BOOL; -static bool isTypeTypedefedAsBOOL(QualType T) { - if (const TypedefType *TT = dyn_cast(T)) - return !strcmp(TT->getDecl()->getName(), "BOOL"); - - return false; -} - -/// getObjCEncodingTypeSize returns size of type for objective-c encoding -/// purpose. -int ASTContext::getObjCEncodingTypeSize(QualType type) { - uint64_t sz = getTypeSize(type); - - // Make all integer and enum types at least as large as an int - if (sz > 0 && type->isIntegralType()) - sz = std::max(sz, getTypeSize(IntTy)); - // Treat arrays as pointers, since that's how they're passed in. - else if (type->isArrayType()) - sz = getTypeSize(VoidPtrTy); - return sz / getTypeSize(CharTy); -} - -/// getObjCEncodingForMethodDecl - Return the encoded type for this method -/// declaration. -void ASTContext::getObjCEncodingForMethodDecl(ObjCMethodDecl *Decl, - std::string& S) -{ - // Encode type qualifer, 'in', 'inout', etc. for the return type. - getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S); - // Encode result type. - getObjCEncodingForType(Decl->getResultType(), S, EncodingRecordTypes); - // Compute size of all parameters. - // Start with computing size of a pointer in number of bytes. - // FIXME: There might(should) be a better way of doing this computation! - SourceLocation Loc; - int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy); - // The first two arguments (self and _cmd) are pointers; account for - // their size. - int ParmOffset = 2 * PtrSize; - int NumOfParams = Decl->getNumParams(); - for (int i = 0; i < NumOfParams; i++) { - QualType PType = Decl->getParamDecl(i)->getType(); - int sz = getObjCEncodingTypeSize (PType); - assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type"); - ParmOffset += sz; - } - S += llvm::utostr(ParmOffset); - S += "@0:"; - S += llvm::utostr(PtrSize); - - // Argument types. - ParmOffset = 2 * PtrSize; - for (int i = 0; i < NumOfParams; i++) { - QualType PType = Decl->getParamDecl(i)->getType(); - // Process argument qualifiers for user supplied arguments; such as, - // 'in', 'inout', etc. - getObjCEncodingForTypeQualifier( - Decl->getParamDecl(i)->getObjCDeclQualifier(), S); - getObjCEncodingForType(PType, S, EncodingRecordTypes); - S += llvm::utostr(ParmOffset); - ParmOffset += getObjCEncodingTypeSize(PType); - } -} - -void ASTContext::getObjCEncodingForType(QualType T, std::string& S, - llvm::SmallVector &ERType) const -{ - // FIXME: This currently doesn't encode: - // @ An object (whether statically typed or typed id) - // # A class object (Class) - // : A method selector (SEL) - // {name=type...} A structure - // (name=type...) A union - // bnum A bit field of num bits - - if (const BuiltinType *BT = T->getAsBuiltinType()) { - char encoding; - switch (BT->getKind()) { - case BuiltinType::Void: - encoding = 'v'; - break; - case BuiltinType::Bool: - encoding = 'B'; - break; - case BuiltinType::Char_U: - case BuiltinType::UChar: - encoding = 'C'; - break; - case BuiltinType::UShort: - encoding = 'S'; - break; - case BuiltinType::UInt: - encoding = 'I'; - break; - case BuiltinType::ULong: - encoding = 'L'; - break; - case BuiltinType::ULongLong: - encoding = 'Q'; - break; - case BuiltinType::Char_S: - case BuiltinType::SChar: - encoding = 'c'; - break; - case BuiltinType::Short: - encoding = 's'; - break; - case BuiltinType::Int: - encoding = 'i'; - break; - case BuiltinType::Long: - encoding = 'l'; - break; - case BuiltinType::LongLong: - encoding = 'q'; - break; - case BuiltinType::Float: - encoding = 'f'; - break; - case BuiltinType::Double: - encoding = 'd'; - break; - case BuiltinType::LongDouble: - encoding = 'd'; - break; - default: - assert(0 && "Unhandled builtin type kind"); - } - - S += encoding; - } - else if (T->isObjCQualifiedIdType()) { - // Treat id same as 'id' for encoding purposes. - return getObjCEncodingForType(getObjCIdType(), S, ERType); - - } - else if (const PointerType *PT = T->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (isObjCIdType(PointeeTy) || PointeeTy->isObjCInterfaceType()) { - S += '@'; - return; - } else if (isObjCClassType(PointeeTy)) { - S += '#'; - return; - } else if (isObjCSelType(PointeeTy)) { - S += ':'; - return; - } - - if (PointeeTy->isCharType()) { - // char pointer types should be encoded as '*' unless it is a - // type that has been typedef'd to 'BOOL'. - if (!isTypeTypedefedAsBOOL(PointeeTy)) { - S += '*'; - return; - } - } - - S += '^'; - getObjCEncodingForType(PT->getPointeeType(), S, ERType); - } else if (const ArrayType *AT = T->getAsArrayType()) { - S += '['; - - if (const ConstantArrayType *CAT = dyn_cast(AT)) - S += llvm::utostr(CAT->getSize().getZExtValue()); - else - assert(0 && "Unhandled array type!"); - - getObjCEncodingForType(AT->getElementType(), S, ERType); - S += ']'; - } else if (T->getAsFunctionType()) { - S += '?'; - } else if (const RecordType *RTy = T->getAsRecordType()) { - RecordDecl *RDecl= RTy->getDecl(); - S += '{'; - S += RDecl->getName(); - bool found = false; - for (unsigned i = 0, e = ERType.size(); i != e; ++i) - if (ERType[i] == RTy) { - found = true; - break; - } - if (!found) { - ERType.push_back(RTy); - S += '='; - for (int i = 0; i < RDecl->getNumMembers(); i++) { - FieldDecl *field = RDecl->getMember(i); - getObjCEncodingForType(field->getType(), S, ERType); - } - assert(ERType.back() == RTy && "Record Type stack mismatch."); - ERType.pop_back(); - } - S += '}'; - } else if (T->isEnumeralType()) { - S += 'i'; - } else - assert(0 && "@encode for type not implemented!"); -} - -void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, - std::string& S) const { - if (QT & Decl::OBJC_TQ_In) - S += 'n'; - if (QT & Decl::OBJC_TQ_Inout) - S += 'N'; - if (QT & Decl::OBJC_TQ_Out) - S += 'o'; - if (QT & Decl::OBJC_TQ_Bycopy) - S += 'O'; - if (QT & Decl::OBJC_TQ_Byref) - S += 'R'; - if (QT & Decl::OBJC_TQ_Oneway) - S += 'V'; -} - -void ASTContext::setBuiltinVaListType(QualType T) -{ - assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!"); - - BuiltinVaListType = T; -} - -void ASTContext::setObjCIdType(TypedefDecl *TD) -{ - assert(ObjCIdType.isNull() && "'id' type already set!"); - - ObjCIdType = getTypedefType(TD); - - // typedef struct objc_object *id; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - assert(ptr && "'id' incorrectly typed"); - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - assert(rec && "'id' incorrectly typed"); - IdStructType = rec; -} - -void ASTContext::setObjCSelType(TypedefDecl *TD) -{ - assert(ObjCSelType.isNull() && "'SEL' type already set!"); - - ObjCSelType = getTypedefType(TD); - - // typedef struct objc_selector *SEL; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - assert(ptr && "'SEL' incorrectly typed"); - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - assert(rec && "'SEL' incorrectly typed"); - SelStructType = rec; -} - -void ASTContext::setObjCProtoType(QualType QT) -{ - assert(ObjCProtoType.isNull() && "'Protocol' type already set!"); - ObjCProtoType = QT; -} - -void ASTContext::setObjCClassType(TypedefDecl *TD) -{ - assert(ObjCClassType.isNull() && "'Class' type already set!"); - - ObjCClassType = getTypedefType(TD); - - // typedef struct objc_class *Class; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - assert(ptr && "'Class' incorrectly typed"); - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - assert(rec && "'Class' incorrectly typed"); - ClassStructType = rec; -} - -void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { - assert(ObjCConstantStringType.isNull() && - "'NSConstantString' type already set!"); - - ObjCConstantStringType = getObjCInterfaceType(Decl); -} - -bool ASTContext::builtinTypesAreCompatible(QualType lhs, QualType rhs) { - const BuiltinType *lBuiltin = lhs->getAsBuiltinType(); - const BuiltinType *rBuiltin = rhs->getAsBuiltinType(); - - return lBuiltin->getKind() == rBuiltin->getKind(); -} - -/// objcTypesAreCompatible - This routine is called when two types -/// are of different class; one is interface type or is -/// a qualified interface type and the other type is of a different class. -/// Example, II or II

. -bool ASTContext::objcTypesAreCompatible(QualType lhs, QualType rhs) { - if (lhs->isObjCInterfaceType() && isObjCIdType(rhs)) - return true; - else if (isObjCIdType(lhs) && rhs->isObjCInterfaceType()) - return true; - if (ObjCInterfaceType *lhsIT = - dyn_cast(lhs.getCanonicalType().getTypePtr())) { - ObjCQualifiedInterfaceType *rhsQI = - dyn_cast(rhs.getCanonicalType().getTypePtr()); - return rhsQI && (lhsIT->getDecl() == rhsQI->getDecl()); - } - else if (ObjCInterfaceType *rhsIT = - dyn_cast(rhs.getCanonicalType().getTypePtr())) { - ObjCQualifiedInterfaceType *lhsQI = - dyn_cast(lhs.getCanonicalType().getTypePtr()); - return lhsQI && (rhsIT->getDecl() == lhsQI->getDecl()); - } - return false; -} - -/// Check that 'lhs' and 'rhs' are compatible interface types. Both types -/// must be canonical types. -bool ASTContext::interfaceTypesAreCompatible(QualType lhs, QualType rhs) { - assert (lhs->isCanonical() && - "interfaceTypesAreCompatible strip typedefs of lhs"); - assert (rhs->isCanonical() && - "interfaceTypesAreCompatible strip typedefs of rhs"); - if (lhs == rhs) - return true; - ObjCInterfaceType *lhsIT = cast(lhs.getTypePtr()); - ObjCInterfaceType *rhsIT = cast(rhs.getTypePtr()); - ObjCInterfaceDecl *rhsIDecl = rhsIT->getDecl(); - ObjCInterfaceDecl *lhsIDecl = lhsIT->getDecl(); - // rhs is derived from lhs it is OK; else it is not OK. - while (rhsIDecl != NULL) { - if (rhsIDecl == lhsIDecl) - return true; - rhsIDecl = rhsIDecl->getSuperClass(); - } - return false; -} - -bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs, - QualType rhs) { - ObjCQualifiedInterfaceType *lhsQI = - dyn_cast(lhs.getCanonicalType().getTypePtr()); - assert(lhsQI && "QualifiedInterfaceTypesAreCompatible - bad lhs type"); - ObjCQualifiedInterfaceType *rhsQI = - dyn_cast(rhs.getCanonicalType().getTypePtr()); - assert(rhsQI && "QualifiedInterfaceTypesAreCompatible - bad rhs type"); - if (!interfaceTypesAreCompatible( - getObjCInterfaceType(lhsQI->getDecl()).getCanonicalType(), - getObjCInterfaceType(rhsQI->getDecl()).getCanonicalType())) - return false; - /* All protocols in lhs must have a presense in rhs. */ - for (unsigned i =0; i < lhsQI->getNumProtocols(); i++) { - bool match = false; - ObjCProtocolDecl *lhsProto = lhsQI->getProtocols(i); - for (unsigned j = 0; j < rhsQI->getNumProtocols(); j++) { - ObjCProtocolDecl *rhsProto = rhsQI->getProtocols(j); - if (lhsProto == rhsProto) { - match = true; - break; - } - } - if (!match) - return false; - } - return true; -} - -/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the -/// inheritance hierarchy of 'rProto'. -static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, - ObjCProtocolDecl *rProto) { - if (lProto == rProto) - return true; - ObjCProtocolDecl** RefPDecl = rProto->getReferencedProtocols(); - for (unsigned i = 0; i < rProto->getNumReferencedProtocols(); i++) - if (ProtocolCompatibleWithProtocol(lProto, RefPDecl[i])) - return true; - return false; -} - -/// ClassImplementsProtocol - Checks that 'lProto' protocol -/// has been implemented in IDecl class, its super class or categories (if -/// lookupCategory is true). -static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, - ObjCInterfaceDecl *IDecl, - bool lookupCategory) { - - // 1st, look up the class. - ObjCProtocolDecl **protoList = IDecl->getReferencedProtocols(); - for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) { - if (ProtocolCompatibleWithProtocol(lProto, protoList[i])) - return true; - } - - // 2nd, look up the category. - if (lookupCategory) - for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) { - protoList = CDecl->getReferencedProtocols(); - for (unsigned i = 0; i < CDecl->getNumReferencedProtocols(); i++) { - if (ProtocolCompatibleWithProtocol(lProto, protoList[i])) - return true; - } - } - - // 3rd, look up the super class(s) - if (IDecl->getSuperClass()) - return - ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory); - - return false; -} - -/// ObjCQualifiedIdTypesAreCompatible - Compares two types, at least -/// one of which is a protocol qualified 'id' type. When 'compare' -/// is true it is for comparison; when false, for assignment/initialization. -bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, - QualType rhs, - bool compare) { - // match id with an 'id' type in all cases. - if (const PointerType *PT = lhs->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) - return true; - - } - else if (const PointerType *PT = rhs->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) - return true; - - } - - ObjCQualifiedInterfaceType *lhsQI = 0; - ObjCQualifiedInterfaceType *rhsQI = 0; - ObjCInterfaceDecl *lhsID = 0; - ObjCInterfaceDecl *rhsID = 0; - ObjCQualifiedIdType *lhsQID = dyn_cast(lhs); - ObjCQualifiedIdType *rhsQID = dyn_cast(rhs); - - if (lhsQID) { - if (!rhsQID && rhs->getTypeClass() == Type::Pointer) { - QualType rtype = - cast(rhs.getCanonicalType())->getPointeeType(); - rhsQI = - dyn_cast( - rtype.getCanonicalType().getTypePtr()); - if (!rhsQI) { - ObjCInterfaceType *IT = dyn_cast( - rtype.getCanonicalType().getTypePtr()); - if (IT) - rhsID = IT->getDecl(); - } - } - if (!rhsQI && !rhsQID && !rhsID) - return false; - - unsigned numRhsProtocols = 0; - ObjCProtocolDecl **rhsProtoList = 0; - if (rhsQI) { - numRhsProtocols = rhsQI->getNumProtocols(); - rhsProtoList = rhsQI->getReferencedProtocols(); - } - else if (rhsQID) { - numRhsProtocols = rhsQID->getNumProtocols(); - rhsProtoList = rhsQID->getReferencedProtocols(); - } - - for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { - ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i); - bool match = false; - - // when comparing an id

on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. - if (rhsID) { - if (ClassImplementsProtocol(lhsProto, rhsID, true)) - match = true; - } - else for (unsigned j = 0; j < numRhsProtocols; j++) { - ObjCProtocolDecl *rhsProto = rhsProtoList[j]; - if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || - compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { - match = true; - break; - } - } - if (!match) - return false; - } - } - else if (rhsQID) { - if (!lhsQID && lhs->getTypeClass() == Type::Pointer) { - QualType ltype = - cast(lhs.getCanonicalType())->getPointeeType(); - lhsQI = - dyn_cast( - ltype.getCanonicalType().getTypePtr()); - if (!lhsQI) { - ObjCInterfaceType *IT = dyn_cast( - ltype.getCanonicalType().getTypePtr()); - if (IT) - lhsID = IT->getDecl(); - } - } - if (!lhsQI && !lhsQID && !lhsID) - return false; - - unsigned numLhsProtocols = 0; - ObjCProtocolDecl **lhsProtoList = 0; - if (lhsQI) { - numLhsProtocols = lhsQI->getNumProtocols(); - lhsProtoList = lhsQI->getReferencedProtocols(); - } - else if (lhsQID) { - numLhsProtocols = lhsQID->getNumProtocols(); - lhsProtoList = lhsQID->getReferencedProtocols(); - } - bool match = false; - // for static type vs. qualified 'id' type, check that class implements - // one of 'id's protocols. - if (lhsID) { - for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { - ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); - if (ClassImplementsProtocol(rhsProto, lhsID, compare)) { - match = true; - break; - } - } - } - else for (unsigned i =0; i < numLhsProtocols; i++) { - match = false; - ObjCProtocolDecl *lhsProto = lhsProtoList[i]; - for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { - ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); - if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || - compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { - match = true; - break; - } - } - } - if (!match) - return false; - } - return true; -} - -bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) { - const VectorType *lVector = lhs->getAsVectorType(); - const VectorType *rVector = rhs->getAsVectorType(); - - if ((lVector->getElementType().getCanonicalType() == - rVector->getElementType().getCanonicalType()) && - (lVector->getNumElements() == rVector->getNumElements())) - return true; - return false; -} - -// C99 6.2.7p1: If both are complete types, then the following additional -// requirements apply...FIXME (handle compatibility across source files). -bool ASTContext::tagTypesAreCompatible(QualType lhs, QualType rhs) { - // "Class" and "id" are compatible built-in structure types. - if (isObjCIdType(lhs) && isObjCClassType(rhs) || - isObjCClassType(lhs) && isObjCIdType(rhs)) - return true; - - // Within a translation unit a tag type is - // only compatible with itself. - return lhs.getCanonicalType() == rhs.getCanonicalType(); -} - -bool ASTContext::pointerTypesAreCompatible(QualType lhs, QualType rhs) { - // C99 6.7.5.1p2: For two pointer types to be compatible, both shall be - // identically qualified and both shall be pointers to compatible types. - if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() || - lhs.getAddressSpace() != rhs.getAddressSpace()) - return false; - - QualType ltype = cast(lhs.getCanonicalType())->getPointeeType(); - QualType rtype = cast(rhs.getCanonicalType())->getPointeeType(); - - return typesAreCompatible(ltype, rtype); -} - -// C++ 5.17p6: When the left operand of an assignment operator denotes a -// reference to T, the operation assigns to the object of type T denoted by the -// reference. -bool ASTContext::referenceTypesAreCompatible(QualType lhs, QualType rhs) { - QualType ltype = lhs; - - if (lhs->isReferenceType()) - ltype = cast(lhs.getCanonicalType())->getReferenceeType(); - - QualType rtype = rhs; - - if (rhs->isReferenceType()) - rtype = cast(rhs.getCanonicalType())->getReferenceeType(); - - return typesAreCompatible(ltype, rtype); -} - -bool ASTContext::functionTypesAreCompatible(QualType lhs, QualType rhs) { - const FunctionType *lbase = cast(lhs.getCanonicalType()); - const FunctionType *rbase = cast(rhs.getCanonicalType()); - const FunctionTypeProto *lproto = dyn_cast(lbase); - const FunctionTypeProto *rproto = dyn_cast(rbase); - - // first check the return types (common between C99 and K&R). - if (!typesAreCompatible(lbase->getResultType(), rbase->getResultType())) - return false; - - if (lproto && rproto) { // two C99 style function prototypes - unsigned lproto_nargs = lproto->getNumArgs(); - unsigned rproto_nargs = rproto->getNumArgs(); - - if (lproto_nargs != rproto_nargs) - return false; - - // both prototypes have the same number of arguments. - if ((lproto->isVariadic() && !rproto->isVariadic()) || - (rproto->isVariadic() && !lproto->isVariadic())) - return false; - - // The use of ellipsis agree...now check the argument types. - for (unsigned i = 0; i < lproto_nargs; i++) - // C99 6.7.5.3p15: ...and each parameter declared with qualified type - // is taken as having the unqualified version of it's declared type. - if (!typesAreCompatible(lproto->getArgType(i).getUnqualifiedType(), - rproto->getArgType(i).getUnqualifiedType())) - return false; - return true; - } - if (!lproto && !rproto) // two K&R style function decls, nothing to do. - return true; - - // we have a mixture of K&R style with C99 prototypes - const FunctionTypeProto *proto = lproto ? lproto : rproto; - - if (proto->isVariadic()) - return false; - - // FIXME: Each parameter type T in the prototype must be compatible with the - // type resulting from applying the usual argument conversions to T. - return true; -} - -bool ASTContext::arrayTypesAreCompatible(QualType lhs, QualType rhs) { - // Compatible arrays must have compatible element types - QualType ltype = lhs->getAsArrayType()->getElementType(); - QualType rtype = rhs->getAsArrayType()->getElementType(); - - if (!typesAreCompatible(ltype, rtype)) - return false; - - // Compatible arrays must be the same size - if (const ConstantArrayType* LCAT = lhs->getAsConstantArrayType()) - if (const ConstantArrayType* RCAT = rhs->getAsConstantArrayType()) - return RCAT->getSize() == LCAT->getSize(); - - return true; -} - -/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, -/// both shall have the identically qualified version of a compatible type. -/// C99 6.2.7p1: Two types have compatible types if their types are the -/// same. See 6.7.[2,3,5] for additional rules. -bool ASTContext::typesAreCompatible(QualType lhs, QualType rhs) { - if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() || - lhs.getAddressSpace() != rhs.getAddressSpace()) - return false; - - QualType lcanon = lhs.getCanonicalType(); - QualType rcanon = rhs.getCanonicalType(); - - // If two types are identical, they are are compatible - if (lcanon == rcanon) - return true; - - // C++ [expr]: If an expression initially has the type "reference to T", the - // type is adjusted to "T" prior to any further analysis, the expression - // designates the object or function denoted by the reference, and the - // expression is an lvalue. - if (ReferenceType *RT = dyn_cast(lcanon)) - lcanon = RT->getReferenceeType(); - if (ReferenceType *RT = dyn_cast(rcanon)) - rcanon = RT->getReferenceeType(); - - Type::TypeClass LHSClass = lcanon->getTypeClass(); - Type::TypeClass RHSClass = rcanon->getTypeClass(); - - // We want to consider the two function types to be the same for these - // comparisons, just force one to the other. - if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto; - if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto; - - // Same as above for arrays - if (LHSClass == Type::VariableArray) LHSClass = Type::ConstantArray; - if (RHSClass == Type::VariableArray) RHSClass = Type::ConstantArray; - if (LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; - if (RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; - - // If the canonical type classes don't match... - if (LHSClass != RHSClass) { - // For Objective-C, it is possible for two types to be compatible - // when their classes don't match (when dealing with "id"). If either type - // is an interface, we defer to objcTypesAreCompatible(). - if (lcanon->isObjCInterfaceType() || rcanon->isObjCInterfaceType()) - return objcTypesAreCompatible(lcanon, rcanon); - - // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, - // a signed integer type, or an unsigned integer type. - if (lcanon->isEnumeralType() && rcanon->isIntegralType()) { - EnumDecl* EDecl = cast(cast(lcanon)->getDecl()); - return EDecl->getIntegerType() == rcanon; - } - if (rcanon->isEnumeralType() && lcanon->isIntegralType()) { - EnumDecl* EDecl = cast(cast(rcanon)->getDecl()); - return EDecl->getIntegerType() == lcanon; - } - - return false; - } - // The canonical type classes match. - switch (LHSClass) { - case Type::FunctionProto: assert(0 && "Canonicalized away above"); - case Type::Pointer: - return pointerTypesAreCompatible(lcanon, rcanon); - case Type::ConstantArray: - case Type::VariableArray: - case Type::IncompleteArray: - return arrayTypesAreCompatible(lcanon, rcanon); - case Type::FunctionNoProto: - return functionTypesAreCompatible(lcanon, rcanon); - case Type::Tagged: // handle structures, unions - return tagTypesAreCompatible(lcanon, rcanon); - case Type::Builtin: - return builtinTypesAreCompatible(lcanon, rcanon); - case Type::ObjCInterface: - return interfaceTypesAreCompatible(lcanon, rcanon); - case Type::Vector: - case Type::OCUVector: - return vectorTypesAreCompatible(lcanon, rcanon); - case Type::ObjCQualifiedInterface: - return QualifiedInterfaceTypesAreCompatible(lcanon, rcanon); - default: - assert(0 && "unexpected type"); - } - return true; // should never get here... -} - -/// Emit - Serialize an ASTContext object to Bitcode. -void ASTContext::Emit(llvm::Serializer& S) const { - S.EmitRef(SourceMgr); - S.EmitRef(Target); - S.EmitRef(Idents); - S.EmitRef(Selectors); - - // Emit the size of the type vector so that we can reserve that size - // when we reconstitute the ASTContext object. - S.EmitInt(Types.size()); - - for (std::vector::const_iterator I=Types.begin(), E=Types.end(); - I!=E;++I) - (*I)->Emit(S); - - // FIXME: S.EmitOwnedPtr(CFConstantStringTypeDecl); -} - -ASTContext* ASTContext::Create(llvm::Deserializer& D) { - SourceManager &SM = D.ReadRef(); - TargetInfo &t = D.ReadRef(); - IdentifierTable &idents = D.ReadRef(); - SelectorTable &sels = D.ReadRef(); - - unsigned size_reserve = D.ReadInt(); - - ASTContext* A = new ASTContext(SM,t,idents,sels,size_reserve); - - for (unsigned i = 0; i < size_reserve; ++i) - Type::Create(*A,i,D); - - // FIXME: A->CFConstantStringTypeDecl = D.ReadOwnedPtr(); - - return A; -} diff --git a/clang/AST/Builtins.cpp b/clang/AST/Builtins.cpp deleted file mode 100644 index e2bf5ca007b..00000000000 --- a/clang/AST/Builtins.cpp +++ /dev/null @@ -1,195 +0,0 @@ -//===--- Builtins.cpp - Builtin function implementation -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements various things for builtin functions. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Builtins.h" -#include "clang/AST/ASTContext.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/TargetInfo.h" -using namespace clang; - -static const Builtin::Info BuiltinInfo[] = { - { "not a builtin function", 0, 0 }, -#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, -#include "clang/AST/Builtins.def" -}; - -const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { - if (ID < Builtin::FirstTSBuiltin) - return BuiltinInfo[ID]; - assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); - return TSRecords[ID - Builtin::FirstTSBuiltin]; -} - - -/// InitializeBuiltins - Mark the identifiers for all the builtins with their -/// appropriate builtin ID # and mark any non-portable builtin identifiers as -/// such. -void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, - const TargetInfo &Target) { - // Step #1: mark all target-independent builtins with their ID's. - for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) - Table.get(BuiltinInfo[i].Name).setBuiltinID(i); - - // Step #2: Get target builtins. - Target.getTargetBuiltins(TSRecords, NumTSRecords); - - // Step #3: Register target-specific builtins. - for (unsigned i = 0, e = NumTSRecords; i != e; ++i) - Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); -} - -/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the -/// pointer over the consumed characters. This returns the resultant type. -static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, - bool AllowTypeModifiers = true) { - // Modifiers. - bool Long = false, LongLong = false, Signed = false, Unsigned = false; - - // Read the modifiers first. - bool Done = false; - while (!Done) { - switch (*Str++) { - default: Done = true; --Str; break; - case 'S': - assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); - assert(!Signed && "Can't use 'S' modifier multiple times!"); - Signed = true; - break; - case 'U': - assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); - assert(!Unsigned && "Can't use 'S' modifier multiple times!"); - Unsigned = true; - break; - case 'L': - assert(!LongLong && "Can't have LLL modifier"); - if (Long) - LongLong = true; - else - Long = true; - break; - } - } - - QualType Type; - - // Read the base type. - switch (*Str++) { - default: assert(0 && "Unknown builtin type letter!"); - case 'v': - assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); - Type = Context.VoidTy; - break; - case 'f': - assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); - Type = Context.FloatTy; - break; - case 'd': - assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); - if (Long) - Type = Context.LongDoubleTy; - else - Type = Context.DoubleTy; - break; - case 's': - assert(!LongLong && "Bad modifiers used with 's'!"); - if (Unsigned) - Type = Context.UnsignedShortTy; - else - Type = Context.ShortTy; - break; - case 'i': - if (LongLong) - Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; - else if (Long) - Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; - else if (Unsigned) - Type = Context.UnsignedIntTy; - else - Type = Context.IntTy; // default is signed. - break; - case 'c': - assert(!Long && !LongLong && "Bad modifiers used with 'c'!"); - if (Signed) - Type = Context.SignedCharTy; - else if (Unsigned) - Type = Context.UnsignedCharTy; - else - Type = Context.CharTy; - break; - case 'z': // size_t. - assert(!Long && !Signed && !Unsigned && "Bad modifiers for 'z'!"); - Type = Context.getSizeType(); - break; - case 'F': - Type = Context.getCFConstantStringType(); - break; - case 'a': - Type = Context.getBuiltinVaListType(); - assert(!Type.isNull() && "builtin va list type not initialized!"); - break; - case 'V': { - char *End; - - unsigned NumElements = strtoul(Str, &End, 10); - assert(End != Str && "Missing vector size"); - - Str = End; - - QualType ElementType = DecodeTypeFromStr(Str, Context, false); - Type = Context.getVectorType(ElementType, NumElements); - break; - } - } - - if (!AllowTypeModifiers) - return Type; - - Done = false; - while (!Done) { - switch (*Str++) { - default: Done = true; --Str; break; - case '*': - Type = Context.getPointerType(Type); - break; - case '&': - Type = Context.getReferenceType(Type); - break; - case 'C': - Type = Type.getQualifiedType(QualType::Const); - break; - } - } - - return Type; -} - -/// GetBuiltinType - Return the type for the specified builtin. -QualType Builtin::Context::GetBuiltinType(unsigned id, - ASTContext &Context) const { - const char *TypeStr = GetRecord(id).Type; - - llvm::SmallVector ArgTypes; - - QualType ResType = DecodeTypeFromStr(TypeStr, Context); - while (TypeStr[0] && TypeStr[0] != '.') - ArgTypes.push_back(DecodeTypeFromStr(TypeStr, Context)); - - assert((TypeStr[0] != '.' || TypeStr[1] == 0) && - "'.' should only occur at end of builtin type list!"); - - // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". - if (ArgTypes.size() == 0 && TypeStr[0] == '.') - return Context.getFunctionTypeNoProto(ResType); - return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(), - TypeStr[0] == '.'); -} diff --git a/clang/AST/CFG.cpp b/clang/AST/CFG.cpp deleted file mode 100644 index e2aba6b3ff3..00000000000 --- a/clang/AST/CFG.cpp +++ /dev/null @@ -1,1509 +0,0 @@ -//===--- CFG.cpp - Classes for representing and building CFGs----*- 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 CFG and CFGBuilder classes for representing and -// building Control-Flow Graphs (CFGs) from ASTs. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/CFG.h" -#include "clang/AST/Expr.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/PrettyPrinter.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/GraphWriter.h" -#include "llvm/Support/Streams.h" -#include "llvm/Support/Compiler.h" -#include -#include -#include -#include -#include - -using namespace clang; - -namespace { - -// SaveAndRestore - A utility class that uses RIIA to save and restore -// the value of a variable. -template -struct VISIBILITY_HIDDEN SaveAndRestore { - SaveAndRestore(T& x) : X(x), old_value(x) {} - ~SaveAndRestore() { X = old_value; } - T get() { return old_value; } - - T& X; - T old_value; -}; - -/// CFGBuilder - This class is implements CFG construction from an AST. -/// The builder is stateful: an instance of the builder should be used to only -/// construct a single CFG. -/// -/// Example usage: -/// -/// CFGBuilder builder; -/// CFG* cfg = builder.BuildAST(stmt1); -/// -/// CFG construction is done via a recursive walk of an AST. -/// We actually parse the AST in reverse order so that the successor -/// of a basic block is constructed prior to its predecessor. This -/// allows us to nicely capture implicit fall-throughs without extra -/// basic blocks. -/// -class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor { - CFG* cfg; - CFGBlock* Block; - CFGBlock* Succ; - CFGBlock* ContinueTargetBlock; - CFGBlock* BreakTargetBlock; - CFGBlock* SwitchTerminatedBlock; - CFGBlock* DefaultCaseBlock; - - // LabelMap records the mapping from Label expressions to their blocks. - typedef llvm::DenseMap LabelMapTy; - LabelMapTy LabelMap; - - // A list of blocks that end with a "goto" that must be backpatched to - // their resolved targets upon completion of CFG construction. - typedef std::vector BackpatchBlocksTy; - BackpatchBlocksTy BackpatchBlocks; - - // A list of labels whose address has been taken (for indirect gotos). - typedef llvm::SmallPtrSet LabelSetTy; - LabelSetTy AddressTakenLabels; - -public: - explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL), - ContinueTargetBlock(NULL), BreakTargetBlock(NULL), - SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) { - // Create an empty CFG. - cfg = new CFG(); - } - - ~CFGBuilder() { delete cfg; } - - // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(Stmt* Statement); - - // Visitors to walk an AST and construct the CFG. Called by - // buildCFG. Do not call directly! - - CFGBlock* VisitStmt(Stmt* Statement); - CFGBlock* VisitNullStmt(NullStmt* Statement); - CFGBlock* VisitCompoundStmt(CompoundStmt* C); - CFGBlock* VisitIfStmt(IfStmt* I); - CFGBlock* VisitReturnStmt(ReturnStmt* R); - CFGBlock* VisitLabelStmt(LabelStmt* L); - CFGBlock* VisitGotoStmt(GotoStmt* G); - CFGBlock* VisitForStmt(ForStmt* F); - CFGBlock* VisitWhileStmt(WhileStmt* W); - CFGBlock* VisitDoStmt(DoStmt* D); - CFGBlock* VisitContinueStmt(ContinueStmt* C); - CFGBlock* VisitBreakStmt(BreakStmt* B); - CFGBlock* VisitSwitchStmt(SwitchStmt* S); - CFGBlock* VisitCaseStmt(CaseStmt* S); - CFGBlock* VisitDefaultStmt(DefaultStmt* D); - CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I); - - // FIXME: Add support for ObjC-specific control-flow structures. - - CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { - badCFG = true; - return Block; - } - - CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S) { - badCFG = true; - return Block; - } - -private: - CFGBlock* createBlock(bool add_successor = true); - CFGBlock* addStmt(Stmt* S); - CFGBlock* WalkAST(Stmt* S, bool AlwaysAddStmt); - CFGBlock* WalkAST_VisitChildren(Stmt* S); - CFGBlock* WalkAST_VisitDeclSubExprs(StmtIterator& I); - CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* S); - void FinishBlock(CFGBlock* B); - - bool badCFG; -}; - -/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can -/// represent an arbitrary statement. Examples include a single expression -/// or a function body (compound statement). The ownership of the returned -/// CFG is transferred to the caller. If CFG construction fails, this method -/// returns NULL. -CFG* CFGBuilder::buildCFG(Stmt* Statement) { - assert (cfg); - if (!Statement) return NULL; - - badCFG = false; - - // Create an empty block that will serve as the exit block for the CFG. - // Since this is the first block added to the CFG, it will be implicitly - // registered as the exit block. - Succ = createBlock(); - assert (Succ == &cfg->getExit()); - Block = NULL; // the EXIT block is empty. Create all other blocks lazily. - - // Visit the statements and create the CFG. - CFGBlock* B = Visit(Statement); - if (!B) B = Succ; - - if (B) { - // Finalize the last constructed block. This usually involves - // reversing the order of the statements in the block. - if (Block) FinishBlock(B); - - // Backpatch the gotos whose label -> block mappings we didn't know - // when we encountered them. - for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), - E = BackpatchBlocks.end(); I != E; ++I ) { - - CFGBlock* B = *I; - GotoStmt* G = cast(B->getTerminator()); - LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); - - // If there is no target for the goto, then we are looking at an - // incomplete AST. Handle this by not registering a successor. - if (LI == LabelMap.end()) continue; - - B->addSuccessor(LI->second); - } - - // Add successors to the Indirect Goto Dispatch block (if we have one). - if (CFGBlock* B = cfg->getIndirectGotoBlock()) - for (LabelSetTy::iterator I = AddressTakenLabels.begin(), - E = AddressTakenLabels.end(); I != E; ++I ) { - - // Lookup the target block. - LabelMapTy::iterator LI = LabelMap.find(*I); - - // If there is no target block that contains label, then we are looking - // at an incomplete AST. Handle this by not registering a successor. - if (LI == LabelMap.end()) continue; - - B->addSuccessor(LI->second); - } - - Succ = B; - } - - // Create an empty entry block that has no predecessors. - cfg->setEntry(createBlock()); - - if (badCFG) { - delete cfg; - cfg = NULL; - return NULL; - } - - // NULL out cfg so that repeated calls to the builder will fail and that - // the ownership of the constructed CFG is passed to the caller. - CFG* t = cfg; - cfg = NULL; - return t; -} - -/// createBlock - Used to lazily create blocks that are connected -/// to the current (global) succcessor. -CFGBlock* CFGBuilder::createBlock(bool add_successor) { - CFGBlock* B = cfg->createBlock(); - if (add_successor && Succ) B->addSuccessor(Succ); - return B; -} - -/// FinishBlock - When the last statement has been added to the block, -/// we must reverse the statements because they have been inserted -/// in reverse order. -void CFGBuilder::FinishBlock(CFGBlock* B) { - assert (B); - B->reverseStmts(); -} - -/// addStmt - Used to add statements/expressions to the current CFGBlock -/// "Block". This method calls WalkAST on the passed statement to see if it -/// contains any short-circuit expressions. If so, it recursively creates -/// the necessary blocks for such expressions. It returns the "topmost" block -/// of the created blocks, or the original value of "Block" when this method -/// was called if no additional blocks are created. -CFGBlock* CFGBuilder::addStmt(Stmt* S) { - if (!Block) Block = createBlock(); - return WalkAST(S,true); -} - -/// WalkAST - Used by addStmt to walk the subtree of a statement and -/// add extra blocks for ternary operators, &&, and ||. We also -/// process "," and DeclStmts (which may contain nested control-flow). -CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) { - switch (S->getStmtClass()) { - case Stmt::ConditionalOperatorClass: { - ConditionalOperator* C = cast(S); - - // Create the confluence block that will "merge" the results - // of the ternary expression. - CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); - ConfluenceBlock->appendStmt(C); - FinishBlock(ConfluenceBlock); - - // 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. - // e.g: x ?: y is shorthand for: x ? x : y; - Succ = ConfluenceBlock; - Block = NULL; - CFGBlock* LHSBlock = NULL; - if (C->getLHS()) { - LHSBlock = Visit(C->getLHS()); - FinishBlock(LHSBlock); - Block = NULL; - } - - // Create the block for the RHS expression. - Succ = ConfluenceBlock; - CFGBlock* RHSBlock = Visit(C->getRHS()); - FinishBlock(RHSBlock); - - // Create the block that will contain the condition. - Block = createBlock(false); - - if (LHSBlock) - Block->addSuccessor(LHSBlock); - else { - // If we have no LHS expression, add the ConfluenceBlock as a direct - // successor for the block containing the condition. Moreover, - // we need to reverse the order of the predecessors in the - // ConfluenceBlock because the RHSBlock will have been added to - // the succcessors already, and we want the first predecessor to the - // the block containing the expression for the case when the ternary - // expression evaluates to true. - Block->addSuccessor(ConfluenceBlock); - assert (ConfluenceBlock->pred_size() == 2); - std::reverse(ConfluenceBlock->pred_begin(), - ConfluenceBlock->pred_end()); - } - - Block->addSuccessor(RHSBlock); - - Block->setTerminator(C); - return addStmt(C->getCond()); - } - - case Stmt::ChooseExprClass: { - ChooseExpr* C = cast(S); - - CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); - ConfluenceBlock->appendStmt(C); - FinishBlock(ConfluenceBlock); - - Succ = ConfluenceBlock; - Block = NULL; - CFGBlock* LHSBlock = Visit(C->getLHS()); - FinishBlock(LHSBlock); - - Succ = ConfluenceBlock; - Block = NULL; - CFGBlock* RHSBlock = Visit(C->getRHS()); - FinishBlock(RHSBlock); - - Block = createBlock(false); - Block->addSuccessor(LHSBlock); - Block->addSuccessor(RHSBlock); - Block->setTerminator(C); - return addStmt(C->getCond()); - } - - case Stmt::DeclStmtClass: { - ScopedDecl* D = cast(S)->getDecl(); - Block->appendStmt(S); - - StmtIterator I(D); - return WalkAST_VisitDeclSubExprs(I); - } - - case Stmt::AddrLabelExprClass: { - AddrLabelExpr* A = cast(S); - AddressTakenLabels.insert(A->getLabel()); - - if (AlwaysAddStmt) Block->appendStmt(S); - return Block; - } - - case Stmt::StmtExprClass: - return WalkAST_VisitStmtExpr(cast(S)); - - case Stmt::UnaryOperatorClass: { - UnaryOperator* U = cast(S); - - // sizeof(expressions). For such expressions, - // the subexpression is not really evaluated, so - // we don't care about control-flow within the sizeof. - if (U->getOpcode() == UnaryOperator::SizeOf) { - Block->appendStmt(S); - return Block; - } - - break; - } - - case Stmt::BinaryOperatorClass: { - BinaryOperator* B = cast(S); - - if (B->isLogicalOp()) { // && or || - CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); - ConfluenceBlock->appendStmt(B); - FinishBlock(ConfluenceBlock); - - // create the block evaluating the LHS - CFGBlock* LHSBlock = createBlock(false); - LHSBlock->setTerminator(B); - - // create the block evaluating the RHS - Succ = ConfluenceBlock; - Block = NULL; - CFGBlock* RHSBlock = Visit(B->getRHS()); - - // Now link the LHSBlock with RHSBlock. - if (B->getOpcode() == BinaryOperator::LOr) { - LHSBlock->addSuccessor(ConfluenceBlock); - LHSBlock->addSuccessor(RHSBlock); - } - else { - assert (B->getOpcode() == BinaryOperator::LAnd); - LHSBlock->addSuccessor(RHSBlock); - LHSBlock->addSuccessor(ConfluenceBlock); - } - - // Generate the blocks for evaluating the LHS. - Block = LHSBlock; - return addStmt(B->getLHS()); - } - else if (B->getOpcode() == BinaryOperator::Comma) { // , - Block->appendStmt(B); - addStmt(B->getRHS()); - return addStmt(B->getLHS()); - } - - break; - } - - case Stmt::ParenExprClass: - return WalkAST(cast(S)->getSubExpr(), AlwaysAddStmt); - - default: - break; - }; - - if (AlwaysAddStmt) Block->appendStmt(S); - return WalkAST_VisitChildren(S); -} - -/// WalkAST_VisitDeclSubExprs - Utility method to handle Decls contained in -/// DeclStmts. Because the initialization code (and sometimes the -/// the type declarations) for DeclStmts can contain arbitrary expressions, -/// we must linearize declarations to handle arbitrary control-flow induced by -/// those expressions. -CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExprs(StmtIterator& I) { - if (I == StmtIterator()) - return Block; - - Stmt* S = *I; - ++I; - WalkAST_VisitDeclSubExprs(I); - - // Optimization: Don't create separate block-level statements for literals. - - switch (S->getStmtClass()) { - case Stmt::IntegerLiteralClass: - case Stmt::CharacterLiteralClass: - case Stmt::StringLiteralClass: - break; - - // All other cases. - - default: - Block = addStmt(S); - } - - return Block; -} - -/// WalkAST_VisitChildren - Utility method to call WalkAST on the -/// children of a Stmt. -CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* S) { - CFGBlock* B = Block; - for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; - I != E; ++I) - if (*I) B = WalkAST(*I); - - return B; -} - -/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement -/// expressions (a GCC extension). -CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* S) { - Block->appendStmt(S); - return VisitCompoundStmt(S->getSubStmt()); -} - -/// VisitStmt - Handle statements with no branching control flow. -CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) { - // We cannot assume that we are in the middle of a basic block, since - // the CFG might only be constructed for this single statement. If - // we have no current basic block, just create one lazily. - if (!Block) Block = createBlock(); - - // Simply add the statement to the current block. We actually - // insert statements in reverse order; this order is reversed later - // when processing the containing element in the AST. - addStmt(Statement); - - return Block; -} - -CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) { - return Block; -} - -CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { - - for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); - I != E; ++I ) { - Visit(*I); - } - - return Block; -} - -CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { - // We may see an if statement in the middle of a basic block, or - // it may be the first statement we are processing. In either case, - // we create a new basic block. First, we create the blocks for - // the then...else statements, and then we create the block containing - // the if statement. If we were in the middle of a block, we - // stop processing that block and reverse its statements. That block - // is then the implicit successor for the "then" and "else" clauses. - - // The block we were proccessing is now finished. Make it the - // successor block. - if (Block) { - Succ = Block; - FinishBlock(Block); - } - - // Process the false branch. NULL out Block so that the recursive - // call to Visit will create a new basic block. - // Null out Block so that all successor - CFGBlock* ElseBlock = Succ; - - if (Stmt* Else = I->getElse()) { - SaveAndRestore sv(Succ); - - // NULL out Block so that the recursive call to Visit will - // create a new basic block. - Block = NULL; - ElseBlock = Visit(Else); - - if (!ElseBlock) // Can occur when the Else body has all NullStmts. - ElseBlock = sv.get(); - else if (Block) - FinishBlock(ElseBlock); - } - - // Process the true branch. NULL out Block so that the recursive - // call to Visit will create a new basic block. - // Null out Block so that all successor - CFGBlock* ThenBlock; - { - Stmt* Then = I->getThen(); - assert (Then); - SaveAndRestore sv(Succ); - Block = NULL; - ThenBlock = Visit(Then); - - if (!ThenBlock) // Can occur when the Then body has all NullStmts. - ThenBlock = sv.get(); - else if (Block) - FinishBlock(ThenBlock); - } - - // Now create a new block containing the if statement. - Block = createBlock(false); - - // Set the terminator of the new block to the If statement. - Block->setTerminator(I); - - // Now add the successors. - Block->addSuccessor(ThenBlock); - Block->addSuccessor(ElseBlock); - - // Add the condition as the last statement in the new block. This - // may create new blocks as the condition may contain control-flow. Any - // newly created blocks will be pointed to be "Block". - return addStmt(I->getCond()->IgnoreParens()); -} - - -CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { - // If we were in the middle of a block we stop processing that block - // and reverse its statements. - // - // NOTE: If a "return" appears in the middle of a block, this means - // that the code afterwards is DEAD (unreachable). We still - // keep a basic block for that code; a simple "mark-and-sweep" - // from the entry block will be able to report such dead - // blocks. - if (Block) FinishBlock(Block); - - // Create the new block. - Block = createBlock(false); - - // The Exit block is the only successor. - Block->addSuccessor(&cfg->getExit()); - - // Add the return statement to the block. This may create new blocks - // if R contains control-flow (short-circuit operations). - return addStmt(R); -} - -CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { - // Get the block of the labeled statement. Add it to our map. - Visit(L->getSubStmt()); - CFGBlock* LabelBlock = Block; - - if (!LabelBlock) // This can happen when the body is empty, i.e. - LabelBlock=createBlock(); // scopes that only contains NullStmts. - - assert (LabelMap.find(L) == LabelMap.end() && "label already in map"); - LabelMap[ L ] = LabelBlock; - - // Labels partition blocks, so this is the end of the basic block - // we were processing (L is the block's label). Because this is - // label (and we have already processed the substatement) there is no - // extra control-flow to worry about. - LabelBlock->setLabel(L); - FinishBlock(LabelBlock); - - // We set Block to NULL to allow lazy creation of a new block - // (if necessary); - Block = NULL; - - // This block is now the implicit successor of other blocks. - Succ = LabelBlock; - - return LabelBlock; -} - -CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) { - // Goto is a control-flow statement. Thus we stop processing the - // current block and create a new one. - if (Block) FinishBlock(Block); - Block = createBlock(false); - Block->setTerminator(G); - - // If we already know the mapping to the label block add the - // successor now. - LabelMapTy::iterator I = LabelMap.find(G->getLabel()); - - if (I == LabelMap.end()) - // We will need to backpatch this block later. - BackpatchBlocks.push_back(Block); - else - Block->addSuccessor(I->second); - - return Block; -} - -CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { - // "for" is a control-flow statement. Thus we stop processing the - // current block. - - CFGBlock* LoopSuccessor = NULL; - - if (Block) { - FinishBlock(Block); - LoopSuccessor = Block; - } - else LoopSuccessor = Succ; - - // Because of short-circuit evaluation, the condition of the loop - // can span multiple basic blocks. Thus we need the "Entry" and "Exit" - // blocks that evaluate the condition. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; - - // Set the terminator for the "exit" condition block. - ExitConditionBlock->setTerminator(F); - - // Now add the actual condition to the condition block. Because the - // condition itself may contain control-flow, new blocks may be created. - if (Stmt* C = F->getCond()) { - Block = ExitConditionBlock; - EntryConditionBlock = addStmt(C); - if (Block) FinishBlock(EntryConditionBlock); - } - - // The condition block is the implicit successor for the loop body as - // well as any code above the loop. - Succ = EntryConditionBlock; - - // Now create the loop body. - { - assert (F->getBody()); - - // Save the current values for Block, Succ, and continue and break targets - SaveAndRestore save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); - - // All continues within this loop should go to the condition block - ContinueTargetBlock = EntryConditionBlock; - - // All breaks should go to the code following the loop. - BreakTargetBlock = LoopSuccessor; - - // Create a new block to contain the (bottom) of the loop body. - Block = NULL; - - // If we have increment code, insert it at the end of the body block. - if (Stmt* I = F->getInc()) Block = addStmt(I); - - // Now populate the body block, and in the process create new blocks - // as we walk the body of the loop. - CFGBlock* BodyBlock = Visit(F->getBody()); - - if (!BodyBlock) - BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;" - else if (Block) - FinishBlock(BodyBlock); - - // This new body block is a successor to our "exit" condition block. - ExitConditionBlock->addSuccessor(BodyBlock); - } - - // Link up the condition block with the code that follows the loop. - // (the false branch). - ExitConditionBlock->addSuccessor(LoopSuccessor); - - // If the loop contains initialization, create a new block for those - // statements. This block can also contain statements that precede - // the loop. - if (Stmt* I = F->getInit()) { - Block = createBlock(); - return addStmt(I); - } - else { - // There is no loop initialization. We are thus basically a while - // loop. NULL out Block to force lazy block construction. - Block = NULL; - Succ = EntryConditionBlock; - return EntryConditionBlock; - } -} - -CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { - // "while" is a control-flow statement. Thus we stop processing the - // current block. - - CFGBlock* LoopSuccessor = NULL; - - if (Block) { - FinishBlock(Block); - LoopSuccessor = Block; - } - else LoopSuccessor = Succ; - - // Because of short-circuit evaluation, the condition of the loop - // can span multiple basic blocks. Thus we need the "Entry" and "Exit" - // blocks that evaluate the condition. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; - - // Set the terminator for the "exit" condition block. - ExitConditionBlock->setTerminator(W); - - // Now add the actual condition to the condition block. Because the - // condition itself may contain control-flow, new blocks may be created. - // Thus we update "Succ" after adding the condition. - if (Stmt* C = W->getCond()) { - Block = ExitConditionBlock; - EntryConditionBlock = addStmt(C); - assert (Block == EntryConditionBlock); - if (Block) FinishBlock(EntryConditionBlock); - } - - // The condition block is the implicit successor for the loop body as - // well as any code above the loop. - Succ = EntryConditionBlock; - - // Process the loop body. - { - assert (W->getBody()); - - // Save the current values for Block, Succ, and continue and break targets - SaveAndRestore save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); - - // All continues within this loop should go to the condition block - ContinueTargetBlock = EntryConditionBlock; - - // All breaks should go to the code following the loop. - BreakTargetBlock = LoopSuccessor; - - // NULL out Block to force lazy instantiation of blocks for the body. - Block = NULL; - - // Create the body. The returned block is the entry to the loop body. - CFGBlock* BodyBlock = Visit(W->getBody()); - - if (!BodyBlock) - BodyBlock = EntryConditionBlock; // can happen for "while(...) ;" - else if (Block) - FinishBlock(BodyBlock); - - // Add the loop body entry as a successor to the condition. - ExitConditionBlock->addSuccessor(BodyBlock); - } - - // Link up the condition block with the code that follows the loop. - // (the false branch). - ExitConditionBlock->addSuccessor(LoopSuccessor); - - // There can be no more statements in the condition block - // since we loop back to this block. NULL out Block to force - // lazy creation of another block. - Block = NULL; - - // Return the condition block, which is the dominating block for the loop. - Succ = EntryConditionBlock; - return EntryConditionBlock; -} - -CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) { - // "do...while" is a control-flow statement. Thus we stop processing the - // current block. - - CFGBlock* LoopSuccessor = NULL; - - if (Block) { - FinishBlock(Block); - LoopSuccessor = Block; - } - else LoopSuccessor = Succ; - - // Because of short-circuit evaluation, the condition of the loop - // can span multiple basic blocks. Thus we need the "Entry" and "Exit" - // blocks that evaluate the condition. - CFGBlock* ExitConditionBlock = createBlock(false); - CFGBlock* EntryConditionBlock = ExitConditionBlock; - - // Set the terminator for the "exit" condition block. - ExitConditionBlock->setTerminator(D); - - // Now add the actual condition to the condition block. Because the - // condition itself may contain control-flow, new blocks may be created. - if (Stmt* C = D->getCond()) { - Block = ExitConditionBlock; - EntryConditionBlock = addStmt(C); - if (Block) FinishBlock(EntryConditionBlock); - } - - // The condition block is the implicit successor for the loop body. - Succ = EntryConditionBlock; - - // Process the loop body. - CFGBlock* BodyBlock = NULL; - { - assert (D->getBody()); - - // Save the current values for Block, Succ, and continue and break targets - SaveAndRestore save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); - - // All continues within this loop should go to the condition block - ContinueTargetBlock = EntryConditionBlock; - - // All breaks should go to the code following the loop. - BreakTargetBlock = LoopSuccessor; - - // NULL out Block to force lazy instantiation of blocks for the body. - Block = NULL; - - // Create the body. The returned block is the entry to the loop body. - BodyBlock = Visit(D->getBody()); - - if (!BodyBlock) - BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)" - else if (Block) - FinishBlock(BodyBlock); - - // Add the loop body entry as a successor to the condition. - ExitConditionBlock->addSuccessor(BodyBlock); - } - - // Link up the condition block with the code that follows the loop. - // (the false branch). - ExitConditionBlock->addSuccessor(LoopSuccessor); - - // There can be no more statements in the body block(s) - // since we loop back to the body. NULL out Block to force - // lazy creation of another block. - Block = NULL; - - // Return the loop body, which is the dominating block for the loop. - Succ = BodyBlock; - return BodyBlock; -} - -CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { - // "continue" is a control-flow statement. Thus we stop processing the - // current block. - if (Block) FinishBlock(Block); - - // Now create a new block that ends with the continue statement. - Block = createBlock(false); - Block->setTerminator(C); - - // If there is no target for the continue, then we are looking at an - // incomplete AST. Handle this by not registering a successor. - if (ContinueTargetBlock) Block->addSuccessor(ContinueTargetBlock); - - return Block; -} - -CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) { - // "break" is a control-flow statement. Thus we stop processing the - // current block. - if (Block) FinishBlock(Block); - - // Now create a new block that ends with the continue statement. - Block = createBlock(false); - Block->setTerminator(B); - - // If there is no target for the break, then we are looking at an - // incomplete AST. Handle this by not registering a successor. - if (BreakTargetBlock) Block->addSuccessor(BreakTargetBlock); - - return Block; -} - -CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* S) { - // "switch" is a control-flow statement. Thus we stop processing the - // current block. - CFGBlock* SwitchSuccessor = NULL; - - if (Block) { - FinishBlock(Block); - SwitchSuccessor = Block; - } - else SwitchSuccessor = Succ; - - // Save the current "switch" context. - SaveAndRestore save_switch(SwitchTerminatedBlock), - save_break(BreakTargetBlock), - save_default(DefaultCaseBlock); - - // Set the "default" case to be the block after the switch statement. - // If the switch statement contains a "default:", this value will - // be overwritten with the block for that code. - DefaultCaseBlock = SwitchSuccessor; - - // Create a new block that will contain the switch statement. - SwitchTerminatedBlock = createBlock(false); - - // Now process the switch body. The code after the switch is the implicit - // successor. - Succ = SwitchSuccessor; - BreakTargetBlock = SwitchSuccessor; - - // When visiting the body, the case statements should automatically get - // linked up to the switch. We also don't keep a pointer to the body, - // since all control-flow from the switch goes to case/default statements. - assert (S->getBody() && "switch must contain a non-NULL body"); - Block = NULL; - CFGBlock *BodyBlock = Visit(S->getBody()); - if (Block) FinishBlock(BodyBlock); - - // If we have no "default:" case, the default transition is to the - // code following the switch body. - SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock); - - // Add the terminator and condition in the switch block. - SwitchTerminatedBlock->setTerminator(S); - assert (S->getCond() && "switch condition must be non-NULL"); - Block = SwitchTerminatedBlock; - - return addStmt(S->getCond()); -} - -CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* S) { - // CaseStmts are essentially labels, so they are the - // first statement in a block. - - if (S->getSubStmt()) Visit(S->getSubStmt()); - CFGBlock* CaseBlock = Block; - if (!CaseBlock) CaseBlock = createBlock(); - - // Cases statements partition blocks, so this is the top of - // the basic block we were processing (the "case XXX:" is the label). - CaseBlock->setLabel(S); - FinishBlock(CaseBlock); - - // Add this block to the list of successors for the block with the - // switch statement. - assert (SwitchTerminatedBlock); - SwitchTerminatedBlock->addSuccessor(CaseBlock); - - // We set Block to NULL to allow lazy creation of a new block (if necessary) - Block = NULL; - - // This block is now the implicit successor of other blocks. - Succ = CaseBlock; - - return CaseBlock; -} - -CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* S) { - if (S->getSubStmt()) Visit(S->getSubStmt()); - DefaultCaseBlock = Block; - if (!DefaultCaseBlock) DefaultCaseBlock = createBlock(); - - // Default statements partition blocks, so this is the top of - // the basic block we were processing (the "default:" is the label). - DefaultCaseBlock->setLabel(S); - FinishBlock(DefaultCaseBlock); - - // Unlike case statements, we don't add the default block to the - // successors for the switch statement immediately. This is done - // when we finish processing the switch statement. This allows for - // the default case (including a fall-through to the code after the - // switch statement) to always be the last successor of a switch-terminated - // block. - - // We set Block to NULL to allow lazy creation of a new block (if necessary) - Block = NULL; - - // This block is now the implicit successor of other blocks. - Succ = DefaultCaseBlock; - - return DefaultCaseBlock; -} - -CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { - // Lazily create the indirect-goto dispatch block if there isn't one - // already. - CFGBlock* IBlock = cfg->getIndirectGotoBlock(); - - if (!IBlock) { - IBlock = createBlock(false); - cfg->setIndirectGotoBlock(IBlock); - } - - // IndirectGoto is a control-flow statement. Thus we stop processing the - // current block and create a new one. - if (Block) FinishBlock(Block); - Block = createBlock(false); - Block->setTerminator(I); - Block->addSuccessor(IBlock); - return addStmt(I->getTarget()); -} - - -} // end anonymous namespace - -/// createBlock - Constructs and adds a new CFGBlock to the CFG. The -/// block has no successors or predecessors. If this is the first block -/// created in the CFG, it is automatically set to be the Entry and Exit -/// of the CFG. -CFGBlock* CFG::createBlock() { - bool first_block = begin() == end(); - - // Create the block. - Blocks.push_front(CFGBlock(NumBlockIDs++)); - - // If this is the first block, set it as the Entry and Exit. - if (first_block) Entry = Exit = &front(); - - // Return the block. - return &front(); -} - -/// buildCFG - Constructs a CFG from an AST. Ownership of the returned -/// CFG is returned to the caller. -CFG* CFG::buildCFG(Stmt* Statement) { - CFGBuilder Builder; - return Builder.buildCFG(Statement); -} - -/// reverseStmts - Reverses the orders of statements within a CFGBlock. -void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); } - -//===----------------------------------------------------------------------===// -// CFG: Queries for BlkExprs. -//===----------------------------------------------------------------------===// - -namespace { - typedef llvm::DenseMap BlkExprMapTy; -} - -static void FindSubExprAssignments(Stmt* S, llvm::SmallPtrSet& Set) { - if (!S) - return; - - for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { - if (!*I) continue; - - if (BinaryOperator* B = dyn_cast(*I)) - if (B->isAssignmentOp()) Set.insert(B); - - FindSubExprAssignments(*I, Set); - } -} - -static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { - BlkExprMapTy* M = new BlkExprMapTy(); - - // Look for assignments that are used as subexpressions. These are the - // only assignments that we want to register as a block-level expression. - llvm::SmallPtrSet SubExprAssignments; - - for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) - for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) - FindSubExprAssignments(*BI, SubExprAssignments); - - // Iterate over the statements again on identify the Expr* and Stmt* at - // the block-level that are block-level expressions. - for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) - for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) - if (Expr* E = dyn_cast(*BI)) { - - if (BinaryOperator* B = dyn_cast(E)) { - // Assignment expressions that are not nested within another - // expression are really "statements" whose value is never - // used by another expression. - if (B->isAssignmentOp() && !SubExprAssignments.count(E)) - continue; - } - else if (const StmtExpr* S = dyn_cast(E)) { - // Special handling for statement expressions. The last statement - // in the statement expression is also a block-level expr. - const CompoundStmt* C = S->getSubStmt(); - if (!C->body_empty()) { - unsigned x = M->size(); - (*M)[C->body_back()] = x; - } - } - - unsigned x = M->size(); - (*M)[E] = x; - } - - return M; -} - -CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { - assert(S != NULL); - if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); } - - BlkExprMapTy* M = reinterpret_cast(BlkExprMap); - BlkExprMapTy::iterator I = M->find(S); - - if (I == M->end()) return CFG::BlkExprNumTy(); - else return CFG::BlkExprNumTy(I->second); -} - -unsigned CFG::getNumBlkExprs() { - if (const BlkExprMapTy* M = reinterpret_cast(BlkExprMap)) - return M->size(); - else { - // We assume callers interested in the number of BlkExprs will want - // the map constructed if it doesn't already exist. - BlkExprMap = (void*) PopulateBlkExprMap(*this); - return reinterpret_cast(BlkExprMap)->size(); - } -} - -typedef std::set > BlkEdgeSetTy; - -const std::pair* -CFG::getBlockEdgeImpl(const CFGBlock* B1, const CFGBlock* B2) { - - BlkEdgeSetTy*& p = reinterpret_cast(BlkEdgeSet); - if (!p) p = new BlkEdgeSetTy(); - - return &*(p->insert(std::make_pair(const_cast(B1), - const_cast(B2))).first); -} - -CFG::~CFG() { - delete reinterpret_cast(BlkExprMap); - delete reinterpret_cast(BlkEdgeSet); -} - -//===----------------------------------------------------------------------===// -// CFG pretty printing -//===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { - - typedef llvm::DenseMap > StmtMapTy; - StmtMapTy StmtMap; - signed CurrentBlock; - unsigned CurrentStmt; - -public: - - StmtPrinterHelper(const CFG* cfg) : CurrentBlock(0), CurrentStmt(0) { - for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { - unsigned j = 1; - for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ; - BI != BEnd; ++BI, ++j ) - StmtMap[*BI] = std::make_pair(I->getBlockID(),j); - } - } - - virtual ~StmtPrinterHelper() {} - - void setBlockID(signed i) { CurrentBlock = i; } - void setStmtID(unsigned i) { CurrentStmt = i; } - - virtual bool handledStmt(Stmt* S, std::ostream& OS) { - - StmtMapTy::iterator I = StmtMap.find(S); - - if (I == StmtMap.end()) - return false; - - if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock - && I->second.second == CurrentStmt) - return false; - - OS << "[B" << I->second.first << "." << I->second.second << "]"; - return true; - } -}; - -class VISIBILITY_HIDDEN CFGBlockTerminatorPrint - : public StmtVisitor { - - std::ostream& OS; - StmtPrinterHelper* Helper; -public: - CFGBlockTerminatorPrint(std::ostream& os, StmtPrinterHelper* helper) - : OS(os), Helper(helper) {} - - void VisitIfStmt(IfStmt* I) { - OS << "if "; - I->getCond()->printPretty(OS,Helper); - } - - // Default case. - void VisitStmt(Stmt* S) { S->printPretty(OS); } - - void VisitForStmt(ForStmt* F) { - OS << "for (" ; - if (F->getInit()) OS << "..."; - OS << "; "; - if (Stmt* C = F->getCond()) C->printPretty(OS,Helper); - OS << "; "; - if (F->getInc()) OS << "..."; - OS << ")"; - } - - void VisitWhileStmt(WhileStmt* W) { - OS << "while " ; - if (Stmt* C = W->getCond()) C->printPretty(OS,Helper); - } - - void VisitDoStmt(DoStmt* D) { - OS << "do ... while "; - if (Stmt* C = D->getCond()) C->printPretty(OS,Helper); - } - - void VisitSwitchStmt(SwitchStmt* S) { - OS << "switch "; - S->getCond()->printPretty(OS,Helper); - } - - void VisitConditionalOperator(ConditionalOperator* C) { - C->getCond()->printPretty(OS,Helper); - OS << " ? ... : ..."; - } - - void VisitChooseExpr(ChooseExpr* C) { - OS << "__builtin_choose_expr( "; - C->getCond()->printPretty(OS,Helper); - OS << " )"; - } - - void VisitIndirectGotoStmt(IndirectGotoStmt* I) { - OS << "goto *"; - I->getTarget()->printPretty(OS,Helper); - } - - void VisitBinaryOperator(BinaryOperator* B) { - if (!B->isLogicalOp()) { - VisitExpr(B); - return; - } - - B->getLHS()->printPretty(OS,Helper); - - switch (B->getOpcode()) { - case BinaryOperator::LOr: - OS << " || ..."; - return; - case BinaryOperator::LAnd: - OS << " && ..."; - return; - default: - assert(false && "Invalid logical operator."); - } - } - - void VisitExpr(Expr* E) { - E->printPretty(OS,Helper); - } -}; - - -void print_stmt(std::ostream&OS, StmtPrinterHelper* Helper, Stmt* S) { - if (Helper) { - // special printing for statement-expressions. - if (StmtExpr* SE = dyn_cast(S)) { - CompoundStmt* Sub = SE->getSubStmt(); - - if (Sub->child_begin() != Sub->child_end()) { - OS << "({ ... ; "; - Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS); - OS << " })\n"; - return; - } - } - - // special printing for comma expressions. - if (BinaryOperator* B = dyn_cast(S)) { - if (B->getOpcode() == BinaryOperator::Comma) { - OS << "... , "; - Helper->handledStmt(B->getRHS(),OS); - OS << '\n'; - return; - } - } - } - - S->printPretty(OS, Helper); - - // Expressions need a newline. - if (isa(S)) OS << '\n'; -} - -void print_block(std::ostream& OS, const CFG* cfg, const CFGBlock& B, - StmtPrinterHelper* Helper, bool print_edges) { - - if (Helper) Helper->setBlockID(B.getBlockID()); - - // Print the header. - OS << "\n [ B" << B.getBlockID(); - - if (&B == &cfg->getEntry()) - OS << " (ENTRY) ]\n"; - else if (&B == &cfg->getExit()) - OS << " (EXIT) ]\n"; - else if (&B == cfg->getIndirectGotoBlock()) - OS << " (INDIRECT GOTO DISPATCH) ]\n"; - else - OS << " ]\n"; - - // Print the label of this block. - if (Stmt* S = const_cast(B.getLabel())) { - - if (print_edges) - OS << " "; - - if (LabelStmt* L = dyn_cast(S)) - OS << L->getName(); - else if (CaseStmt* C = dyn_cast(S)) { - OS << "case "; - C->getLHS()->printPretty(OS); - if (C->getRHS()) { - OS << " ... "; - C->getRHS()->printPretty(OS); - } - } - else if (isa(S)) - OS << "default"; - else - assert(false && "Invalid label statement in CFGBlock."); - - OS << ":\n"; - } - - // Iterate through the statements in the block and print them. - unsigned j = 1; - - for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; - I != E ; ++I, ++j ) { - - // Print the statement # in the basic block and the statement itself. - if (print_edges) - OS << " "; - - OS << std::setw(3) << j << ": "; - - if (Helper) - Helper->setStmtID(j); - - print_stmt(OS,Helper,*I); - } - - // Print the terminator of this block. - if (B.getTerminator()) { - if (print_edges) - OS << " "; - - OS << " T: "; - - if (Helper) Helper->setBlockID(-1); - - CFGBlockTerminatorPrint TPrinter(OS,Helper); - TPrinter.Visit(const_cast(B.getTerminator())); - OS << '\n'; - } - - if (print_edges) { - // Print the predecessors of this block. - OS << " Predecessors (" << B.pred_size() << "):"; - unsigned i = 0; - - for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end(); - I != E; ++I, ++i) { - - if (i == 8 || (i-8) == 0) - OS << "\n "; - - OS << " B" << (*I)->getBlockID(); - } - - OS << '\n'; - - // Print the successors of this block. - OS << " Successors (" << B.succ_size() << "):"; - i = 0; - - for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); - I != E; ++I, ++i) { - - if (i == 8 || (i-8) % 10 == 0) - OS << "\n "; - - OS << " B" << (*I)->getBlockID(); - } - - OS << '\n'; - } -} - -} // end anonymous namespace - -/// dump - A simple pretty printer of a CFG that outputs to stderr. -void CFG::dump() const { print(*llvm::cerr.stream()); } - -/// print - A simple pretty printer of a CFG that outputs to an ostream. -void CFG::print(std::ostream& OS) const { - - StmtPrinterHelper Helper(this); - - // Print the entry block. - print_block(OS, this, getEntry(), &Helper, true); - - // Iterate through the CFGBlocks and print them one by one. - for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { - // Skip the entry block, because we already printed it. - if (&(*I) == &getEntry() || &(*I) == &getExit()) - continue; - - print_block(OS, this, *I, &Helper, true); - } - - // Print the exit block. - print_block(OS, this, getExit(), &Helper, true); -} - -/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. -void CFGBlock::dump(const CFG* cfg) const { print(*llvm::cerr.stream(), cfg); } - -/// print - A simple pretty printer of a CFGBlock that outputs to an ostream. -/// Generally this will only be called from CFG::print. -void CFGBlock::print(std::ostream& OS, const CFG* cfg) const { - StmtPrinterHelper Helper(cfg); - print_block(OS, cfg, *this, &Helper, true); -} - -/// printTerminator - A simple pretty printer of the terminator of a CFGBlock. -void CFGBlock::printTerminator(std::ostream& OS) const { - CFGBlockTerminatorPrint TPrinter(OS,NULL); - TPrinter.Visit(const_cast(getTerminator())); -} - - -//===----------------------------------------------------------------------===// -// CFG Graphviz Visualization -//===----------------------------------------------------------------------===// - - -#ifndef NDEBUG -static StmtPrinterHelper* GraphHelper; -#endif - -void CFG::viewCFG() const { -#ifndef NDEBUG - StmtPrinterHelper H(this); - GraphHelper = &H; - llvm::ViewGraph(this,"CFG"); - GraphHelper = NULL; -#else - std::cerr << "CFG::viewCFG is only available in debug builds on " - << "systems with Graphviz or gv!\n"; -#endif -} - -namespace llvm { -template<> -struct DOTGraphTraits : public DefaultDOTGraphTraits { - static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { - -#ifndef NDEBUG - std::ostringstream Out; - print_block(Out,Graph, *Node, GraphHelper, false); - std::string OutStr = Out.str(); - - if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); - - // Process string output to make it nicer... - for (unsigned i = 0; i != OutStr.length(); ++i) - if (OutStr[i] == '\n') { // Left justify - OutStr[i] = '\\'; - OutStr.insert(OutStr.begin()+i+1, 'l'); - } - - return OutStr; -#else - return ""; -#endif - } -}; -} // end namespace llvm diff --git a/clang/AST/Decl.cpp b/clang/AST/Decl.cpp deleted file mode 100644 index 7fa679cbc08..00000000000 --- a/clang/AST/Decl.cpp +++ /dev/null @@ -1,652 +0,0 @@ -//===--- Decl.cpp - Declaration AST Node Implementation -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Decl class and subclasses. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/Basic/IdentifierTable.h" -#include "llvm/ADT/DenseMap.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Statistics -//===----------------------------------------------------------------------===// - -// temporary statistics gathering -static unsigned nFuncs = 0; -static unsigned nBlockVars = 0; -static unsigned nFileVars = 0; -static unsigned nParmVars = 0; -static unsigned nSUC = 0; -static unsigned nEnumConst = 0; -static unsigned nEnumDecls = 0; -static unsigned nTypedef = 0; -static unsigned nFieldDecls = 0; -static unsigned nInterfaceDecls = 0; -static unsigned nClassDecls = 0; -static unsigned nMethodDecls = 0; -static unsigned nProtocolDecls = 0; -static unsigned nForwardProtocolDecls = 0; -static unsigned nCategoryDecls = 0; -static unsigned nIvarDecls = 0; -static unsigned nObjCImplementationDecls = 0; -static unsigned nObjCCategoryImpl = 0; -static unsigned nObjCCompatibleAlias = 0; -static unsigned nObjCPropertyDecl = 0; -static unsigned nLinkageSpecDecl = 0; -static unsigned nFileScopeAsmDecl = 0; - -static bool StatSwitch = false; - -// This keeps track of all decl attributes. Since so few decls have attrs, we -// keep them in a hash map instead of wasting space in the Decl class. -typedef llvm::DenseMap DeclAttrMapTy; - -static DeclAttrMapTy *DeclAttrs = 0; - -const char *Decl::getDeclKindName() const { - switch (DeclKind) { - default: assert(0 && "Unknown decl kind!"); - case Typedef: return "Typedef"; - case Function: return "Function"; - case BlockVar: return "BlockVar"; - case FileVar: return "FileVar"; - case ParmVar: return "ParmVar"; - case EnumConstant: return "EnumConstant"; - case ObjCInterface: return "ObjCInterface"; - case ObjCClass: return "ObjCClass"; - case ObjCMethod: return "ObjCMethod"; - case ObjCProtocol: return "ObjCProtocol"; - case ObjCForwardProtocol: return "ObjCForwardProtocol"; - case Struct: return "Struct"; - case Union: return "Union"; - case Class: return "Class"; - case Enum: return "Enum"; - } -} - -bool Decl::CollectingStats(bool Enable) { - if (Enable) - StatSwitch = true; - return StatSwitch; -} - -void Decl::PrintStats() { - fprintf(stderr, "*** Decl Stats:\n"); - fprintf(stderr, " %d decls total.\n", - int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+ - nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+ - nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls)); - fprintf(stderr, " %d function decls, %d each (%d bytes)\n", - nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl))); - fprintf(stderr, " %d block variable decls, %d each (%d bytes)\n", - nBlockVars, (int)sizeof(BlockVarDecl), - int(nBlockVars*sizeof(BlockVarDecl))); - fprintf(stderr, " %d file variable decls, %d each (%d bytes)\n", - nFileVars, (int)sizeof(FileVarDecl), - int(nFileVars*sizeof(FileVarDecl))); - fprintf(stderr, " %d parameter variable decls, %d each (%d bytes)\n", - nParmVars, (int)sizeof(ParmVarDecl), - int(nParmVars*sizeof(ParmVarDecl))); - fprintf(stderr, " %d field decls, %d each (%d bytes)\n", - nFieldDecls, (int)sizeof(FieldDecl), - int(nFieldDecls*sizeof(FieldDecl))); - fprintf(stderr, " %d struct/union/class decls, %d each (%d bytes)\n", - nSUC, (int)sizeof(RecordDecl), - int(nSUC*sizeof(RecordDecl))); - fprintf(stderr, " %d enum decls, %d each (%d bytes)\n", - nEnumDecls, (int)sizeof(EnumDecl), - int(nEnumDecls*sizeof(EnumDecl))); - fprintf(stderr, " %d enum constant decls, %d each (%d bytes)\n", - nEnumConst, (int)sizeof(EnumConstantDecl), - int(nEnumConst*sizeof(EnumConstantDecl))); - fprintf(stderr, " %d typedef decls, %d each (%d bytes)\n", - nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl))); - // Objective-C decls... - fprintf(stderr, " %d interface decls, %d each (%d bytes)\n", - nInterfaceDecls, (int)sizeof(ObjCInterfaceDecl), - int(nInterfaceDecls*sizeof(ObjCInterfaceDecl))); - fprintf(stderr, " %d instance variable decls, %d each (%d bytes)\n", - nIvarDecls, (int)sizeof(ObjCIvarDecl), - int(nIvarDecls*sizeof(ObjCIvarDecl))); - fprintf(stderr, " %d class decls, %d each (%d bytes)\n", - nClassDecls, (int)sizeof(ObjCClassDecl), - int(nClassDecls*sizeof(ObjCClassDecl))); - fprintf(stderr, " %d method decls, %d each (%d bytes)\n", - nMethodDecls, (int)sizeof(ObjCMethodDecl), - int(nMethodDecls*sizeof(ObjCMethodDecl))); - fprintf(stderr, " %d protocol decls, %d each (%d bytes)\n", - nProtocolDecls, (int)sizeof(ObjCProtocolDecl), - int(nProtocolDecls*sizeof(ObjCProtocolDecl))); - fprintf(stderr, " %d forward protocol decls, %d each (%d bytes)\n", - nForwardProtocolDecls, (int)sizeof(ObjCForwardProtocolDecl), - int(nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl))); - fprintf(stderr, " %d category decls, %d each (%d bytes)\n", - nCategoryDecls, (int)sizeof(ObjCCategoryDecl), - int(nCategoryDecls*sizeof(ObjCCategoryDecl))); - - fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n", - nObjCImplementationDecls, (int)sizeof(ObjCImplementationDecl), - int(nObjCImplementationDecls*sizeof(ObjCImplementationDecl))); - - fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n", - nObjCCategoryImpl, (int)sizeof(ObjCCategoryImplDecl), - int(nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl))); - - fprintf(stderr, " %d compatibility alias decls, %d each (%d bytes)\n", - nObjCCompatibleAlias, (int)sizeof(ObjCCompatibleAliasDecl), - int(nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl))); - - fprintf(stderr, " %d property decls, %d each (%d bytes)\n", - nObjCPropertyDecl, (int)sizeof(ObjCPropertyDecl), - int(nObjCPropertyDecl*sizeof(ObjCPropertyDecl))); - - fprintf(stderr, "Total bytes = %d\n", - int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+ - nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ - nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ - nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ - nTypedef*sizeof(TypedefDecl)+ - nInterfaceDecls*sizeof(ObjCInterfaceDecl)+ - nIvarDecls*sizeof(ObjCIvarDecl)+ - nClassDecls*sizeof(ObjCClassDecl)+ - nMethodDecls*sizeof(ObjCMethodDecl)+ - nProtocolDecls*sizeof(ObjCProtocolDecl)+ - nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl)+ - nCategoryDecls*sizeof(ObjCCategoryDecl)+ - nObjCImplementationDecls*sizeof(ObjCImplementationDecl)+ - nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl)+ - nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl)+ - nObjCPropertyDecl*sizeof(ObjCPropertyDecl)+ - nLinkageSpecDecl*sizeof(LinkageSpecDecl)+ - nFileScopeAsmDecl*sizeof(FileScopeAsmDecl))); - -} - -void Decl::addDeclKind(Kind k) { - switch (k) { - case Typedef: nTypedef++; break; - case Function: nFuncs++; break; - case BlockVar: nBlockVars++; break; - case FileVar: nFileVars++; break; - case ParmVar: nParmVars++; break; - case EnumConstant: nEnumConst++; break; - case Field: nFieldDecls++; break; - case Struct: case Union: case Class: nSUC++; break; - case Enum: nEnumDecls++; break; - case ObjCInterface: nInterfaceDecls++; break; - case ObjCClass: nClassDecls++; break; - case ObjCMethod: nMethodDecls++; break; - case ObjCProtocol: nProtocolDecls++; break; - case ObjCForwardProtocol: nForwardProtocolDecls++; break; - case ObjCCategory: nCategoryDecls++; break; - case ObjCIvar: nIvarDecls++; break; - case ObjCImplementation: nObjCImplementationDecls++; break; - case ObjCCategoryImpl: nObjCCategoryImpl++; break; - case CompatibleAlias: nObjCCompatibleAlias++; break; - case PropertyDecl: nObjCPropertyDecl++; break; - case LinkageSpec: nLinkageSpecDecl++; break; - case FileScopeAsm: nFileScopeAsmDecl++; break; - } -} - -//===----------------------------------------------------------------------===// -// Decl Allocation/Deallocation Method Implementations -//===----------------------------------------------------------------------===// - -BlockVarDecl *BlockVarDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, - StorageClass S, ScopedDecl *PrevDecl) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) BlockVarDecl(L, Id, T, S, PrevDecl); -} - - -FileVarDecl *FileVarDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, StorageClass S, - ScopedDecl *PrevDecl) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) FileVarDecl(L, Id, T, S, PrevDecl); -} - -ParmVarDecl *ParmVarDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, StorageClass S, - ScopedDecl *PrevDecl) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) ParmVarDecl(L, Id, T, S, PrevDecl); -} - -FunctionDecl *FunctionDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, - StorageClass S, bool isInline, - ScopedDecl *PrevDecl) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) FunctionDecl(L, Id, T, S, isInline, PrevDecl); -} - - -EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, - Expr *E, const llvm::APSInt &V, - ScopedDecl *PrevDecl){ - void *Mem = C.getAllocator().Allocate(); - return new (Mem) EnumConstantDecl(L, Id, T, E, V, PrevDecl); -} - -TypedefDecl *TypedefDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, - ScopedDecl *PD) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) TypedefDecl(L, Id, T, PD); -} - -EnumDecl *EnumDecl::Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id, - ScopedDecl *PrevDecl) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) EnumDecl(L, Id, PrevDecl); -} - -RecordDecl *RecordDecl::Create(ASTContext &C, Kind DK, SourceLocation L, - IdentifierInfo *Id, ScopedDecl *PrevDecl) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) RecordDecl(DK, L, Id, PrevDecl); -} - - -//===----------------------------------------------------------------------===// -// Decl Implementation -//===----------------------------------------------------------------------===// - -// Out-of-line virtual method providing a home for Decl. -Decl::~Decl() { - if (!HasAttrs) - return; - - DeclAttrMapTy::iterator it = DeclAttrs->find(this); - assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!"); - - delete it->second; - DeclAttrs->erase(it); - if (DeclAttrs->empty()) { - delete DeclAttrs; - DeclAttrs = 0; - } -} - -void Decl::addAttr(Attr *NewAttr) { - if (!DeclAttrs) - DeclAttrs = new llvm::DenseMap(); - - Attr *&ExistingAttr = (*DeclAttrs)[this]; - - NewAttr->setNext(ExistingAttr); - ExistingAttr = NewAttr; - - HasAttrs = true; -} - -const Attr *Decl::getAttrs() const { - if (!HasAttrs) - return 0; - - return (*DeclAttrs)[this]; -} - -const char *NamedDecl::getName() const { - if (const IdentifierInfo *II = getIdentifier()) - return II->getName(); - return ""; -} - -FunctionDecl::~FunctionDecl() { - delete[] ParamInfo; -} - -unsigned FunctionDecl::getNumParams() const { - if (isa(getCanonicalType())) - return 0; - return cast(getCanonicalType())->getNumArgs(); -} - -void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { - assert(ParamInfo == 0 && "Already has param info!"); - assert(NumParams == getNumParams() && "Parameter count mismatch!"); - - // Zero params -> null pointer. - if (NumParams) { - ParamInfo = new ParmVarDecl*[NumParams]; - memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); - } -} - - -/// defineBody - When created, RecordDecl's correspond to a forward declared -/// record. This method is used to mark the decl as being defined, with the -/// specified contents. -void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) { - assert(!isDefinition() && "Cannot redefine record!"); - setDefinition(true); - NumMembers = numMembers; - if (numMembers) { - Members = new FieldDecl*[numMembers]; - memcpy(Members, members, numMembers*sizeof(Decl*)); - } -} - -FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { - if (Members == 0 || NumMembers < 0) - return 0; - - // linear search. When C++ classes come along, will likely need to revisit. - for (int i = 0; i < NumMembers; ++i) { - if (Members[i]->getIdentifier() == name) - return Members[i]; - } - return 0; -} - -//===----------------------------------------------------------------------===// -// Objective-C Decl Implementation -//===----------------------------------------------------------------------===// - -void ObjCMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo, - unsigned NumParams) { - assert(ParamInfo == 0 && "Already has param info!"); - - // Zero params -> null pointer. - if (NumParams) { - ParamInfo = new ParmVarDecl*[NumParams]; - memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); - NumMethodParams = NumParams; - } -} - -ObjCMethodDecl::~ObjCMethodDecl() { - delete[] ParamInfo; -} - -/// ObjCAddInstanceVariablesToClass - Inserts instance variables -/// into ObjCInterfaceDecl's fields. -/// -void ObjCInterfaceDecl::addInstanceVariablesToClass(ObjCIvarDecl **ivars, - unsigned numIvars, - SourceLocation RBrac) { - NumIvars = numIvars; - if (numIvars) { - Ivars = new ObjCIvarDecl*[numIvars]; - memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); - } - setLocEnd(RBrac); -} - -/// ObjCAddInstanceVariablesToClassImpl - Checks for correctness of Instance -/// Variables (Ivars) relative to what declared in @implementation;s class. -/// Ivars into ObjCImplementationDecl's fields. -/// -void ObjCImplementationDecl::ObjCAddInstanceVariablesToClassImpl( - ObjCIvarDecl **ivars, unsigned numIvars) { - NumIvars = numIvars; - if (numIvars) { - Ivars = new ObjCIvarDecl*[numIvars]; - memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); - } -} - -/// addMethods - Insert instance and methods declarations into -/// ObjCInterfaceDecl's InsMethods and ClsMethods fields. -/// -void ObjCInterfaceDecl::addMethods(ObjCMethodDecl **insMethods, - unsigned numInsMembers, - ObjCMethodDecl **clsMethods, - unsigned numClsMembers, - SourceLocation endLoc) { - NumInstanceMethods = numInsMembers; - if (numInsMembers) { - InstanceMethods = new ObjCMethodDecl*[numInsMembers]; - memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); - } - NumClassMethods = numClsMembers; - if (numClsMembers) { - ClassMethods = new ObjCMethodDecl*[numClsMembers]; - memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); - } - AtEndLoc = endLoc; -} - -/// addMethods - Insert instance and methods declarations into -/// ObjCProtocolDecl's ProtoInsMethods and ProtoClsMethods fields. -/// -void ObjCProtocolDecl::addMethods(ObjCMethodDecl **insMethods, - unsigned numInsMembers, - ObjCMethodDecl **clsMethods, - unsigned numClsMembers, - SourceLocation endLoc) { - NumInstanceMethods = numInsMembers; - if (numInsMembers) { - InstanceMethods = new ObjCMethodDecl*[numInsMembers]; - memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); - } - NumClassMethods = numClsMembers; - if (numClsMembers) { - ClassMethods = new ObjCMethodDecl*[numClsMembers]; - memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); - } - AtEndLoc = endLoc; -} - -/// addMethods - Insert instance and methods declarations into -/// ObjCCategoryDecl's CatInsMethods and CatClsMethods fields. -/// -void ObjCCategoryDecl::addMethods(ObjCMethodDecl **insMethods, - unsigned numInsMembers, - ObjCMethodDecl **clsMethods, - unsigned numClsMembers, - SourceLocation endLoc) { - NumInstanceMethods = numInsMembers; - if (numInsMembers) { - InstanceMethods = new ObjCMethodDecl*[numInsMembers]; - memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); - } - NumClassMethods = numClsMembers; - if (numClsMembers) { - ClassMethods = new ObjCMethodDecl*[numClsMembers]; - memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); - } - AtEndLoc = endLoc; -} - -ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( - IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { - ObjCInterfaceDecl* ClassDecl = this; - while (ClassDecl != NULL) { - for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end(); - I != E; ++I) { - if ((*I)->getIdentifier() == ID) { - clsDeclared = ClassDecl; - return *I; - } - } - ClassDecl = ClassDecl->getSuperClass(); - } - return NULL; -} - -/// lookupInstanceMethod - This method returns an instance method by looking in -/// the class, its categories, and its super classes (using a linear search). -ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) { - ObjCInterfaceDecl* ClassDecl = this; - ObjCMethodDecl *MethodDecl = 0; - - while (ClassDecl != NULL) { - if ((MethodDecl = ClassDecl->getInstanceMethod(Sel))) - return MethodDecl; - - // Didn't find one yet - look through protocols. - ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); - int numProtocols = ClassDecl->getNumIntfRefProtocols(); - for (int pIdx = 0; pIdx < numProtocols; pIdx++) { - if ((MethodDecl = protocols[pIdx]->getInstanceMethod(Sel))) - return MethodDecl; - } - // Didn't find one yet - now look through categories. - ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); - while (CatDecl) { - if ((MethodDecl = CatDecl->getInstanceMethod(Sel))) - return MethodDecl; - CatDecl = CatDecl->getNextClassCategory(); - } - ClassDecl = ClassDecl->getSuperClass(); - } - return NULL; -} - -// lookupClassMethod - This method returns a class method by looking in the -// class, its categories, and its super classes (using a linear search). -ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { - ObjCInterfaceDecl* ClassDecl = this; - ObjCMethodDecl *MethodDecl = 0; - - while (ClassDecl != NULL) { - if ((MethodDecl = ClassDecl->getClassMethod(Sel))) - return MethodDecl; - - // Didn't find one yet - look through protocols. - ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); - int numProtocols = ClassDecl->getNumIntfRefProtocols(); - for (int pIdx = 0; pIdx < numProtocols; pIdx++) { - if ((MethodDecl = protocols[pIdx]->getClassMethod(Sel))) - return MethodDecl; - } - // Didn't find one yet - now look through categories. - ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); - while (CatDecl) { - if ((MethodDecl = CatDecl->getClassMethod(Sel))) - return MethodDecl; - CatDecl = CatDecl->getNextClassCategory(); - } - ClassDecl = ClassDecl->getSuperClass(); - } - return NULL; -} - -/// lookupInstanceMethod - This method returns an instance method by looking in -/// the class implementation. Unlike interfaces, we don't look outside the -/// implementation. -ObjCMethodDecl *ObjCImplementationDecl::getInstanceMethod(Selector Sel) { - for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) - if ((*I)->getSelector() == Sel) - return *I; - return NULL; -} - -/// lookupClassMethod - This method returns a class method by looking in -/// the class implementation. Unlike interfaces, we don't look outside the -/// implementation. -ObjCMethodDecl *ObjCImplementationDecl::getClassMethod(Selector Sel) { - for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); - I != E; ++I) - if ((*I)->getSelector() == Sel) - return *I; - return NULL; -} - -// lookupInstanceMethod - This method returns an instance method by looking in -// the class implementation. Unlike interfaces, we don't look outside the -// implementation. -ObjCMethodDecl *ObjCCategoryImplDecl::getInstanceMethod(Selector Sel) { - for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) - if ((*I)->getSelector() == Sel) - return *I; - return NULL; -} - -// lookupClassMethod - This method returns an instance method by looking in -// the class implementation. Unlike interfaces, we don't look outside the -// implementation. -ObjCMethodDecl *ObjCCategoryImplDecl::getClassMethod(Selector Sel) { - for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); - I != E; ++I) - if ((*I)->getSelector() == Sel) - return *I; - return NULL; -} - -// lookupInstanceMethod - Lookup a instance method in the protocol and protocols -// it inherited. -ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) { - ObjCMethodDecl *MethodDecl = NULL; - - if ((MethodDecl = getInstanceMethod(Sel))) - return MethodDecl; - - if (getNumReferencedProtocols() > 0) { - ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); - - for (unsigned i = 0; i < getNumReferencedProtocols(); i++) { - if ((MethodDecl = RefPDecl[i]->getInstanceMethod(Sel))) - return MethodDecl; - } - } - return NULL; -} - -// lookupInstanceMethod - Lookup a class method in the protocol and protocols -// it inherited. -ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { - ObjCMethodDecl *MethodDecl = NULL; - - if ((MethodDecl = getClassMethod(Sel))) - return MethodDecl; - - if (getNumReferencedProtocols() > 0) { - ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); - - for(unsigned i = 0; i < getNumReferencedProtocols(); i++) { - if ((MethodDecl = RefPDecl[i]->getClassMethod(Sel))) - return MethodDecl; - } - } - return NULL; -} - -/// getSynthesizedMethodSize - Compute size of synthesized method name -/// as done be the rewrite. -/// -unsigned ObjCMethodDecl::getSynthesizedMethodSize() const { - // syntesized method name is a concatenation of -/+[class-name selector] - // Get length of this name. - unsigned length = 3; // _I_ or _C_ - length += strlen(getClassInterface()->getName()) +1; // extra for _ - NamedDecl *MethodContext = getMethodContext(); - if (ObjCCategoryImplDecl *CID = - dyn_cast(MethodContext)) - length += strlen(CID->getName()) +1; - length += getSelector().getName().size(); // selector name - return length; -} - -ObjCInterfaceDecl *const ObjCMethodDecl::getClassInterface() const { - if (ObjCInterfaceDecl *ID = dyn_cast(MethodContext)) - return ID; - if (ObjCCategoryDecl *CD = dyn_cast(MethodContext)) - return CD->getClassInterface(); - if (ObjCImplementationDecl *IMD = - dyn_cast(MethodContext)) - return IMD->getClassInterface(); - if (ObjCCategoryImplDecl *CID = - dyn_cast(MethodContext)) - return CID->getClassInterface(); - assert(false && "unknown method context"); - return 0; -} diff --git a/clang/AST/DeclSerialization.cpp b/clang/AST/DeclSerialization.cpp deleted file mode 100644 index a7eaed5b2ef..00000000000 --- a/clang/AST/DeclSerialization.cpp +++ /dev/null @@ -1,463 +0,0 @@ -//===--- DeclSerialization.cpp - Serialization of Decls ---------*- 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 methods that implement bitcode serialization for Decls. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Decl.h" -#include "clang/AST/Expr.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using llvm::Serializer; -using llvm::Deserializer; -using llvm::SerializedPtrID; - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Decl Serialization: Dispatch code to handle specialized decl types. -//===----------------------------------------------------------------------===// - -void Decl::Emit(Serializer& S) const { - S.EmitInt(getKind()); - EmitImpl(S); -} - -Decl* Decl::Create(Deserializer& D) { - - Kind k = static_cast(D.ReadInt()); - - switch (k) { - default: - assert (false && "Not implemented."); - break; - - case BlockVar: - return BlockVarDecl::CreateImpl(D); - - case Enum: - return EnumDecl::CreateImpl(D); - - case EnumConstant: - return EnumConstantDecl::CreateImpl(D); - - case Field: - return FieldDecl::CreateImpl(D); - - case FileVar: - return FileVarDecl::CreateImpl(D); - - case ParmVar: - return ParmVarDecl::CreateImpl(D); - - case Function: - return FunctionDecl::CreateImpl(D); - - case Union: - case Struct: - return RecordDecl::CreateImpl(k,D); - - case Typedef: - return TypedefDecl::CreateImpl(D); - - case FileScopeAsm: - return FileScopeAsmDecl::CreateImpl(D); - } -} - -//===----------------------------------------------------------------------===// -// Common serialization logic for subclasses of Decl. -//===----------------------------------------------------------------------===// - -void Decl::EmitInRec(Serializer& S) const { - S.Emit(getLocation()); // From Decl. -} - -void Decl::ReadInRec(Deserializer& D) { - Loc = SourceLocation::ReadVal(D); // From Decl. -} - -//===----------------------------------------------------------------------===// -// Common serialization logic for subclasses of NamedDecl. -//===----------------------------------------------------------------------===// - -void NamedDecl::EmitInRec(Serializer& S) const { - Decl::EmitInRec(S); - S.EmitPtr(getIdentifier()); // From NamedDecl. -} - -void NamedDecl::ReadInRec(Deserializer& D) { - Decl::ReadInRec(D); - D.ReadPtr(Identifier); // From NamedDecl. -} - -//===----------------------------------------------------------------------===// -// Common serialization logic for subclasses of ScopedDecl. -//===----------------------------------------------------------------------===// - -void ScopedDecl::EmitInRec(Serializer& S) const { - NamedDecl::EmitInRec(S); - S.EmitPtr(getNext()); // From ScopedDecl. -} - -void ScopedDecl::ReadInRec(Deserializer& D) { - NamedDecl::ReadInRec(D); - D.ReadPtr(Next); // From ScopedDecl. -} - - //===------------------------------------------------------------===// - // NOTE: Not all subclasses of ScopedDecl will use the "OutRec" // - // methods. This is because owned pointers are usually "batched" // - // together for efficiency. // - //===------------------------------------------------------------===// - -void ScopedDecl::EmitOutRec(Serializer& S) const { - S.EmitOwnedPtr(getNextDeclarator()); // From ScopedDecl. -} - -void ScopedDecl::ReadOutRec(Deserializer& D) { - NextDeclarator = - cast_or_null(D.ReadOwnedPtr()); // From ScopedDecl. -} - -//===----------------------------------------------------------------------===// -// Common serialization logic for subclasses of ValueDecl. -//===----------------------------------------------------------------------===// - -void ValueDecl::EmitInRec(Serializer& S) const { - ScopedDecl::EmitInRec(S); - S.Emit(getType()); // From ValueDecl. -} - -void ValueDecl::ReadInRec(Deserializer& D) { - ScopedDecl::ReadInRec(D); - DeclType = QualType::ReadVal(D); // From ValueDecl. -} - -//===----------------------------------------------------------------------===// -// Common serialization logic for subclasses of VarDecl. -//===----------------------------------------------------------------------===// - -void VarDecl::EmitInRec(Serializer& S) const { - ValueDecl::EmitInRec(S); - S.EmitInt(getStorageClass()); // From VarDecl. -} - -void VarDecl::ReadInRec(Deserializer& D) { - ValueDecl::ReadInRec(D); - SClass = static_cast(D.ReadInt()); // From VarDecl. -} - - //===------------------------------------------------------------===// - // NOTE: VarDecl has its own "OutRec" methods that doesn't use // - // the one define in ScopedDecl. This is to batch emit the // - // owned pointers, which results in a smaller output. - //===------------------------------------------------------------===// - -void VarDecl::EmitOutRec(Serializer& S) const { - // Emit these last because they will create records of their own. - S.BatchEmitOwnedPtrs(getInit(), // From VarDecl. - getNextDeclarator()); // From ScopedDecl. -} - -void VarDecl::ReadOutRec(Deserializer& D) { - Decl* next_declarator; - - D.BatchReadOwnedPtrs(Init, // From VarDecl. - next_declarator); // From ScopedDecl. - - setNextDeclarator(cast_or_null(next_declarator)); -} - - -void VarDecl::EmitImpl(Serializer& S) const { - VarDecl::EmitInRec(S); - VarDecl::EmitOutRec(S); -} - -void VarDecl::ReadImpl(Deserializer& D) { - ReadInRec(D); - ReadOutRec(D); -} - -//===----------------------------------------------------------------------===// -// BlockVarDecl Serialization. -//===----------------------------------------------------------------------===// - -BlockVarDecl* BlockVarDecl::CreateImpl(Deserializer& D) { - BlockVarDecl* decl = - new BlockVarDecl(SourceLocation(),NULL,QualType(),None,NULL); - - decl->VarDecl::ReadImpl(D); - - return decl; -} - -//===----------------------------------------------------------------------===// -// FileVarDecl Serialization. -//===----------------------------------------------------------------------===// - -FileVarDecl* FileVarDecl::CreateImpl(Deserializer& D) { - FileVarDecl* decl = - new FileVarDecl(SourceLocation(),NULL,QualType(),None,NULL); - - decl->VarDecl::ReadImpl(D); - - return decl; -} - -//===----------------------------------------------------------------------===// -// ParmDecl Serialization. -//===----------------------------------------------------------------------===// - -void ParmVarDecl::EmitImpl(llvm::Serializer& S) const { - VarDecl::EmitImpl(S); - S.EmitInt(getObjCDeclQualifier()); // From ParmVarDecl. -} - -ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D) { - ParmVarDecl* decl = - new ParmVarDecl(SourceLocation(),NULL,QualType(),None,NULL); - - decl->VarDecl::ReadImpl(D); - decl->objcDeclQualifier = static_cast(D.ReadInt()); - - return decl; -} - -//===----------------------------------------------------------------------===// -// EnumDecl Serialization. -//===----------------------------------------------------------------------===// - -void EnumDecl::EmitImpl(Serializer& S) const { - ScopedDecl::EmitInRec(S); - S.EmitBool(isDefinition()); - S.Emit(IntegerType); - S.BatchEmitOwnedPtrs(ElementList,getNextDeclarator()); -} - -EnumDecl* EnumDecl::CreateImpl(Deserializer& D) { - EnumDecl* decl = new EnumDecl(SourceLocation(),NULL,NULL); - - decl->ScopedDecl::ReadInRec(D); - decl->setDefinition(D.ReadBool()); - decl->IntegerType = QualType::ReadVal(D); - - Decl* next_declarator; - Decl* Elist; - - D.BatchReadOwnedPtrs(Elist,next_declarator); - - decl->ElementList = cast_or_null(Elist); - decl->setNextDeclarator(cast_or_null(next_declarator)); - - return decl; -} - -//===----------------------------------------------------------------------===// -// EnumConstantDecl Serialization. -//===----------------------------------------------------------------------===// - -void EnumConstantDecl::EmitImpl(Serializer& S) const { - S.Emit(Val); - ValueDecl::EmitInRec(S); - S.BatchEmitOwnedPtrs(getNextDeclarator(),Init); -} - -EnumConstantDecl* EnumConstantDecl::CreateImpl(Deserializer& D) { - llvm::APSInt val(1); - D.Read(val); - - EnumConstantDecl* decl = - new EnumConstantDecl(SourceLocation(),NULL,QualType(),NULL, - val,NULL); - - decl->ValueDecl::ReadInRec(D); - - Decl* next_declarator; - - D.BatchReadOwnedPtrs(next_declarator,decl->Init); - - decl->setNextDeclarator(cast_or_null(next_declarator)); - - return decl; -} - -//===----------------------------------------------------------------------===// -// FieldDecl Serialization. -//===----------------------------------------------------------------------===// - -void FieldDecl::EmitImpl(Serializer& S) const { - S.Emit(getType()); - NamedDecl::EmitInRec(S); - S.EmitOwnedPtr(BitWidth); -} - -FieldDecl* FieldDecl::CreateImpl(Deserializer& D) { - FieldDecl* decl = new FieldDecl(SourceLocation(),NULL,QualType()); - decl->DeclType.ReadBackpatch(D); - decl->ReadInRec(D); - decl->BitWidth = D.ReadOwnedPtr(); - return decl; -} - -//===----------------------------------------------------------------------===// -// FunctionDecl Serialization. -//===----------------------------------------------------------------------===// - -void FunctionDecl::EmitImpl(Serializer& S) const { - S.EmitInt(SClass); // From FunctionDecl. - S.EmitBool(IsInline); // From FunctionDecl. - ValueDecl::EmitInRec(S); - S.EmitPtr(DeclChain); - - // NOTE: We do not need to serialize out the number of parameters, because - // that is encoded in the type (accessed via getNumParams()). - - if (ParamInfo != NULL) { - S.EmitBool(true); - S.BatchEmitOwnedPtrs(getNumParams(),&ParamInfo[0], Body, - getNextDeclarator()); - } - else { - S.EmitBool(false); - S.BatchEmitOwnedPtrs(Body,getNextDeclarator()); - } -} - -FunctionDecl* FunctionDecl::CreateImpl(Deserializer& D) { - StorageClass SClass = static_cast(D.ReadInt()); - bool IsInline = D.ReadBool(); - - FunctionDecl* decl = - new FunctionDecl(SourceLocation(),NULL,QualType(),SClass, IsInline, 0); - - decl->ValueDecl::ReadInRec(D); - D.ReadPtr(decl->DeclChain); - - Decl* next_declarator; - - bool hasParamDecls = D.ReadBool(); - - decl->ParamInfo = hasParamDecls - ? new ParmVarDecl*[decl->getNumParams()] - : NULL; - - if (hasParamDecls) - D.BatchReadOwnedPtrs(decl->getNumParams(), - reinterpret_cast(&decl->ParamInfo[0]), - decl->Body, next_declarator); - else - D.BatchReadOwnedPtrs(decl->Body, next_declarator); - - decl->setNextDeclarator(cast_or_null(next_declarator)); - - return decl; -} - -//===----------------------------------------------------------------------===// -// RecordDecl Serialization. -//===----------------------------------------------------------------------===// - -void RecordDecl::EmitImpl(Serializer& S) const { - ScopedDecl::EmitInRec(S); - S.EmitBool(isDefinition()); - S.EmitBool(hasFlexibleArrayMember()); - S.EmitSInt(getNumMembers()); - if (getNumMembers() > 0) { - assert (Members); - S.BatchEmitOwnedPtrs((unsigned) getNumMembers(), - (Decl**) &Members[0],getNextDeclarator()); - } - else - ScopedDecl::EmitOutRec(S); -} - -RecordDecl* RecordDecl::CreateImpl(Decl::Kind DK, Deserializer& D) { - RecordDecl* decl = new RecordDecl(DK,SourceLocation(),NULL,NULL); - - decl->ScopedDecl::ReadInRec(D); - decl->setDefinition(D.ReadBool()); - decl->setHasFlexibleArrayMember(D.ReadBool()); - decl->NumMembers = D.ReadSInt(); - - if (decl->getNumMembers() > 0) { - Decl* next_declarator; - decl->Members = new FieldDecl*[(unsigned) decl->getNumMembers()]; - - D.BatchReadOwnedPtrs((unsigned) decl->getNumMembers(), - (Decl**) &decl->Members[0], - next_declarator); - - decl->setNextDeclarator(cast_or_null(next_declarator)); - } - else - decl->ScopedDecl::ReadOutRec(D); - - return decl; -} - -//===----------------------------------------------------------------------===// -// TypedefDecl Serialization. -//===----------------------------------------------------------------------===// - -void TypedefDecl::EmitImpl(Serializer& S) const { - S.Emit(UnderlyingType); - ScopedDecl::EmitInRec(S); - ScopedDecl::EmitOutRec(S); -} - -TypedefDecl* TypedefDecl::CreateImpl(Deserializer& D) { - QualType T = QualType::ReadVal(D); - - TypedefDecl* decl = new TypedefDecl(SourceLocation(),NULL,T,NULL); - - decl->ScopedDecl::ReadInRec(D); - decl->ScopedDecl::ReadOutRec(D); - - return decl; -} - -//===----------------------------------------------------------------------===// -// LinkageSpec Serialization. -//===----------------------------------------------------------------------===// - -void LinkageSpecDecl::EmitInRec(Serializer& S) const { - Decl::EmitInRec(S); - S.EmitInt(getLanguage()); - S.EmitPtr(D); -} - -void LinkageSpecDecl::ReadInRec(Deserializer& D) { - Decl::ReadInRec(D); - Language = static_cast(D.ReadInt()); - D.ReadPtr(this->D); -} - -//===----------------------------------------------------------------------===// -// FileScopeAsm Serialization. -//===----------------------------------------------------------------------===// - -void FileScopeAsmDecl::EmitImpl(llvm::Serializer& S) const -{ - Decl::EmitInRec(S); - S.EmitOwnedPtr(AsmString); -} - -FileScopeAsmDecl* FileScopeAsmDecl::CreateImpl(Deserializer& D) { - FileScopeAsmDecl* decl = new FileScopeAsmDecl(SourceLocation(), 0); - - decl->Decl::ReadInRec(D); - decl->AsmString = cast(D.ReadOwnedPtr()); -// D.ReadOwnedPtr(D.ReadOwnedPtr())<#T * * Ptr#>, <#bool AutoRegister#>)(decl->AsmString); - - return decl; -} diff --git a/clang/AST/Expr.cpp b/clang/AST/Expr.cpp deleted file mode 100644 index 11fcc419a51..00000000000 --- a/clang/AST/Expr.cpp +++ /dev/null @@ -1,1391 +0,0 @@ -//===--- Expr.cpp - Expression AST Node Implementation --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Expr class and subclasses. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Expr.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/TargetInfo.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Primary Expressions. -//===----------------------------------------------------------------------===// - -StringLiteral::StringLiteral(const char *strData, unsigned byteLength, - bool Wide, QualType t, SourceLocation firstLoc, - SourceLocation lastLoc) : - Expr(StringLiteralClass, t) { - // OPTIMIZE: could allocate this appended to the StringLiteral. - char *AStrData = new char[byteLength]; - memcpy(AStrData, strData, byteLength); - StrData = AStrData; - ByteLength = byteLength; - IsWide = Wide; - firstTokLoc = firstLoc; - lastTokLoc = lastLoc; -} - -StringLiteral::~StringLiteral() { - delete[] StrData; -} - -bool UnaryOperator::isPostfix(Opcode Op) { - switch (Op) { - case PostInc: - case PostDec: - return true; - default: - return false; - } -} - -/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it -/// corresponds to, e.g. "sizeof" or "[pre]++". -const char *UnaryOperator::getOpcodeStr(Opcode Op) { - switch (Op) { - default: assert(0 && "Unknown unary operator"); - case PostInc: return "++"; - case PostDec: return "--"; - case PreInc: return "++"; - case PreDec: return "--"; - case AddrOf: return "&"; - case Deref: return "*"; - case Plus: return "+"; - case Minus: return "-"; - case Not: return "~"; - case LNot: return "!"; - case Real: return "__real"; - case Imag: return "__imag"; - case SizeOf: return "sizeof"; - case AlignOf: return "alignof"; - case Extension: return "__extension__"; - case OffsetOf: return "__builtin_offsetof"; - } -} - -//===----------------------------------------------------------------------===// -// Postfix Operators. -//===----------------------------------------------------------------------===// - - -CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t, - SourceLocation rparenloc) - : Expr(CallExprClass, t), NumArgs(numargs) { - SubExprs = new Expr*[numargs+1]; - SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) - SubExprs[i+ARGS_START] = args[i]; - RParenLoc = rparenloc; -} - -/// setNumArgs - This changes the number of arguments present in this call. -/// Any orphaned expressions are deleted by this, and any new operands are set -/// to null. -void CallExpr::setNumArgs(unsigned NumArgs) { - // No change, just return. - if (NumArgs == getNumArgs()) return; - - // If shrinking # arguments, just delete the extras and forgot them. - if (NumArgs < getNumArgs()) { - for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) - delete getArg(i); - this->NumArgs = NumArgs; - return; - } - - // Otherwise, we are growing the # arguments. New an bigger argument array. - Expr **NewSubExprs = new Expr*[NumArgs+1]; - // Copy over args. - for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) - NewSubExprs[i] = SubExprs[i]; - // Null out new args. - for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) - NewSubExprs[i] = 0; - - delete[] SubExprs; - SubExprs = NewSubExprs; - this->NumArgs = NumArgs; -} - -bool CallExpr::isBuiltinConstantExpr() const { - // All simple function calls (e.g. func()) are implicitly cast to pointer to - // function. As a result, we try and obtain the DeclRefExpr from the - // ImplicitCastExpr. - const ImplicitCastExpr *ICE = dyn_cast(getCallee()); - if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). - return false; - - const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); - if (!DRE) - return false; - - const FunctionDecl *FDecl = dyn_cast(DRE->getDecl()); - if (!FDecl) - return false; - - unsigned builtinID = FDecl->getIdentifier()->getBuiltinID(); - if (!builtinID) - return false; - - // We have a builtin that is a constant expression - if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString) - return true; - return false; -} - -bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const { - // The following enum mimics gcc's internal "typeclass.h" file. - enum gcc_type_class { - no_type_class = -1, - void_type_class, integer_type_class, char_type_class, - enumeral_type_class, boolean_type_class, - pointer_type_class, reference_type_class, offset_type_class, - real_type_class, complex_type_class, - function_type_class, method_type_class, - record_type_class, union_type_class, - array_type_class, string_type_class, - lang_type_class - }; - Result.setIsSigned(true); - - // All simple function calls (e.g. func()) are implicitly cast to pointer to - // function. As a result, we try and obtain the DeclRefExpr from the - // ImplicitCastExpr. - const ImplicitCastExpr *ICE = dyn_cast(getCallee()); - if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). - return false; - const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); - if (!DRE) - return false; - - // We have a DeclRefExpr. - if (strcmp(DRE->getDecl()->getName(), "__builtin_classify_type") == 0) { - // If no argument was supplied, default to "no_type_class". This isn't - // ideal, however it's what gcc does. - Result = static_cast(no_type_class); - if (NumArgs >= 1) { - QualType argType = getArg(0)->getType(); - - if (argType->isVoidType()) - Result = void_type_class; - else if (argType->isEnumeralType()) - Result = enumeral_type_class; - else if (argType->isBooleanType()) - Result = boolean_type_class; - else if (argType->isCharType()) - Result = string_type_class; // gcc doesn't appear to use char_type_class - else if (argType->isIntegerType()) - Result = integer_type_class; - else if (argType->isPointerType()) - Result = pointer_type_class; - else if (argType->isReferenceType()) - Result = reference_type_class; - else if (argType->isRealType()) - Result = real_type_class; - else if (argType->isComplexType()) - Result = complex_type_class; - else if (argType->isFunctionType()) - Result = function_type_class; - else if (argType->isStructureType()) - Result = record_type_class; - else if (argType->isUnionType()) - Result = union_type_class; - else if (argType->isArrayType()) - Result = array_type_class; - else if (argType->isUnionType()) - Result = union_type_class; - else // FIXME: offset_type_class, method_type_class, & lang_type_class? - assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); - } - return true; - } - return false; -} - -/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it -/// corresponds to, e.g. "<<=". -const char *BinaryOperator::getOpcodeStr(Opcode Op) { - switch (Op) { - default: assert(0 && "Unknown binary operator"); - case Mul: return "*"; - case Div: return "/"; - case Rem: return "%"; - case Add: return "+"; - case Sub: return "-"; - case Shl: return "<<"; - case Shr: return ">>"; - case LT: return "<"; - case GT: return ">"; - case LE: return "<="; - case GE: return ">="; - case EQ: return "=="; - case NE: return "!="; - case And: return "&"; - case Xor: return "^"; - case Or: return "|"; - case LAnd: return "&&"; - case LOr: return "||"; - case Assign: return "="; - case MulAssign: return "*="; - case DivAssign: return "/="; - case RemAssign: return "%="; - case AddAssign: return "+="; - case SubAssign: return "-="; - case ShlAssign: return "<<="; - case ShrAssign: return ">>="; - case AndAssign: return "&="; - case XorAssign: return "^="; - case OrAssign: return "|="; - case Comma: return ","; - } -} - -InitListExpr::InitListExpr(SourceLocation lbraceloc, - Expr **initexprs, unsigned numinits, - SourceLocation rbraceloc) - : Expr(InitListExprClass, QualType()) - , NumInits(numinits) - , LBraceLoc(lbraceloc) - , RBraceLoc(rbraceloc) -{ - InitExprs = new Expr*[numinits]; - for (unsigned i = 0; i != numinits; i++) - InitExprs[i] = initexprs[i]; -} - -//===----------------------------------------------------------------------===// -// Generic Expression Routines -//===----------------------------------------------------------------------===// - -/// hasLocalSideEffect - Return true if this immediate expression has side -/// effects, not counting any sub-expressions. -bool Expr::hasLocalSideEffect() const { - switch (getStmtClass()) { - default: - return false; - case ParenExprClass: - return cast(this)->getSubExpr()->hasLocalSideEffect(); - case UnaryOperatorClass: { - const UnaryOperator *UO = cast(this); - - switch (UO->getOpcode()) { - default: return false; - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - return true; // ++/-- - - case UnaryOperator::Deref: - // Dereferencing a volatile pointer is a side-effect. - return getType().isVolatileQualified(); - case UnaryOperator::Real: - case UnaryOperator::Imag: - // accessing a piece of a volatile complex is a side-effect. - return UO->getSubExpr()->getType().isVolatileQualified(); - - case UnaryOperator::Extension: - return UO->getSubExpr()->hasLocalSideEffect(); - } - } - case BinaryOperatorClass: { - const BinaryOperator *BinOp = cast(this); - // Consider comma to have side effects if the LHS and RHS both do. - if (BinOp->getOpcode() == BinaryOperator::Comma) - return BinOp->getLHS()->hasLocalSideEffect() && - BinOp->getRHS()->hasLocalSideEffect(); - - return BinOp->isAssignmentOp(); - } - case CompoundAssignOperatorClass: - return true; - - case ConditionalOperatorClass: { - const ConditionalOperator *Exp = cast(this); - return Exp->getCond()->hasLocalSideEffect() - || (Exp->getLHS() && Exp->getLHS()->hasLocalSideEffect()) - || (Exp->getRHS() && Exp->getRHS()->hasLocalSideEffect()); - } - - case MemberExprClass: - case ArraySubscriptExprClass: - // If the base pointer or element is to a volatile pointer/field, accessing - // if is a side effect. - return getType().isVolatileQualified(); - - case CallExprClass: - // TODO: check attributes for pure/const. "void foo() { strlen("bar"); }" - // should warn. - return true; - case ObjCMessageExprClass: - return true; - - case CastExprClass: - // If this is a cast to void, check the operand. Otherwise, the result of - // the cast is unused. - if (getType()->isVoidType()) - return cast(this)->getSubExpr()->hasLocalSideEffect(); - return false; - } -} - -/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an -/// incomplete type other than void. Nonarray expressions that can be lvalues: -/// - name, where name must be a variable -/// - e[i] -/// - (e), where e must be an lvalue -/// - e.name, where e must be an lvalue -/// - e->name -/// - *e, the type of e cannot be a function type -/// - string-constant -/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension] -/// - reference type [C++ [expr]] -/// -Expr::isLvalueResult Expr::isLvalue() const { - // first, check the type (C99 6.3.2.1) - if (TR->isFunctionType()) // from isObjectType() - return LV_NotObjectType; - - // Allow qualified void which is an incomplete type other than void (yuck). - if (TR->isVoidType() && !TR.getCanonicalType().getCVRQualifiers()) - return LV_IncompleteVoidType; - - if (TR->isReferenceType()) // C++ [expr] - return LV_Valid; - - // the type looks fine, now check the expression - switch (getStmtClass()) { - case StringLiteralClass: // C99 6.5.1p4 - return LV_Valid; - case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2)))) - // For vectors, make sure base is an lvalue (i.e. not a function call). - if (cast(this)->getBase()->getType()->isVectorType()) - return cast(this)->getBase()->isLvalue(); - return LV_Valid; - case DeclRefExprClass: // C99 6.5.1p2 - if (isa(cast(this)->getDecl())) - return LV_Valid; - break; - case MemberExprClass: { // C99 6.5.2.3p4 - const MemberExpr *m = cast(this); - return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(); - } - case UnaryOperatorClass: - if (cast(this)->getOpcode() == UnaryOperator::Deref) - return LV_Valid; // C99 6.5.3p4 - - if (cast(this)->getOpcode() == UnaryOperator::Real || - cast(this)->getOpcode() == UnaryOperator::Imag) - return cast(this)->getSubExpr()->isLvalue(); // GNU. - break; - case ParenExprClass: // C99 6.5.1p5 - return cast(this)->getSubExpr()->isLvalue(); - case CompoundLiteralExprClass: // C99 6.5.2.5p5 - return LV_Valid; - case OCUVectorElementExprClass: - if (cast(this)->containsDuplicateElements()) - return LV_DuplicateVectorComponents; - return LV_Valid; - case ObjCIvarRefExprClass: // ObjC instance variables are lvalues. - return LV_Valid; - case PreDefinedExprClass: - return LV_Valid; - default: - break; - } - return LV_InvalidExpression; -} - -/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, -/// does not have an incomplete type, does not have a const-qualified type, and -/// if it is a structure or union, does not have any member (including, -/// recursively, any member or element of all contained aggregates or unions) -/// with a const-qualified type. -Expr::isModifiableLvalueResult Expr::isModifiableLvalue() const { - isLvalueResult lvalResult = isLvalue(); - - switch (lvalResult) { - case LV_Valid: break; - case LV_NotObjectType: return MLV_NotObjectType; - case LV_IncompleteVoidType: return MLV_IncompleteVoidType; - case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; - case LV_InvalidExpression: return MLV_InvalidExpression; - } - if (TR.isConstQualified()) - return MLV_ConstQualified; - if (TR->isArrayType()) - return MLV_ArrayType; - if (TR->isIncompleteType()) - return MLV_IncompleteType; - - if (const RecordType *r = dyn_cast(TR.getCanonicalType())) { - if (r->hasConstFields()) - return MLV_ConstQualified; - } - return MLV_Valid; -} - -/// hasGlobalStorage - Return true if this expression has static storage -/// duration. This means that the address of this expression is a link-time -/// constant. -bool Expr::hasGlobalStorage() const { - switch (getStmtClass()) { - default: - return false; - case ParenExprClass: - return cast(this)->getSubExpr()->hasGlobalStorage(); - case ImplicitCastExprClass: - return cast(this)->getSubExpr()->hasGlobalStorage(); - case CompoundLiteralExprClass: - return cast(this)->isFileScope(); - case DeclRefExprClass: { - const Decl *D = cast(this)->getDecl(); - if (const VarDecl *VD = dyn_cast(D)) - return VD->hasGlobalStorage(); - return false; - } - case MemberExprClass: { - const MemberExpr *M = cast(this); - return !M->isArrow() && M->getBase()->hasGlobalStorage(); - } - case ArraySubscriptExprClass: - return cast(this)->getBase()->hasGlobalStorage(); - case PreDefinedExprClass: - return true; - } -} - -Expr* Expr::IgnoreParens() { - Expr* E = this; - while (ParenExpr* P = dyn_cast(E)) - E = P->getSubExpr(); - - return E; -} - -/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr -/// or CastExprs or ImplicitCastExprs, returning their operand. -Expr *Expr::IgnoreParenCasts() { - Expr *E = this; - while (true) { - if (ParenExpr *P = dyn_cast(E)) - E = P->getSubExpr(); - else if (CastExpr *P = dyn_cast(E)) - E = P->getSubExpr(); - else if (ImplicitCastExpr *P = dyn_cast(E)) - E = P->getSubExpr(); - else - return E; - } -} - - -bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { - switch (getStmtClass()) { - default: - if (Loc) *Loc = getLocStart(); - return false; - case ParenExprClass: - return cast(this)->getSubExpr()->isConstantExpr(Ctx, Loc); - case StringLiteralClass: - case ObjCStringLiteralClass: - case FloatingLiteralClass: - case IntegerLiteralClass: - case CharacterLiteralClass: - case ImaginaryLiteralClass: - case TypesCompatibleExprClass: - case CXXBoolLiteralExprClass: - return true; - case CallExprClass: { - const CallExpr *CE = cast(this); - llvm::APSInt Result(32); - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - if (CE->isBuiltinClassifyType(Result)) - return true; - if (CE->isBuiltinConstantExpr()) - return true; - if (Loc) *Loc = getLocStart(); - return false; - } - case DeclRefExprClass: { - const Decl *D = cast(this)->getDecl(); - // Accept address of function. - if (isa(D) || isa(D)) - return true; - if (Loc) *Loc = getLocStart(); - if (isa(D)) - return TR->isArrayType(); - return false; - } - case CompoundLiteralExprClass: - if (Loc) *Loc = getLocStart(); - // Allow "(int []){2,4}", since the array will be converted to a pointer. - // Allow "(vector type){2,4}" since the elements are all constant. - return TR->isArrayType() || TR->isVectorType(); - case UnaryOperatorClass: { - const UnaryOperator *Exp = cast(this); - - // C99 6.6p9 - if (Exp->getOpcode() == UnaryOperator::AddrOf) { - if (!Exp->getSubExpr()->hasGlobalStorage()) { - if (Loc) *Loc = getLocStart(); - return false; - } - return true; - } - - // Get the operand value. If this is sizeof/alignof, do not evalute the - // operand. This affects C99 6.6p3. - if (!Exp->isSizeOfAlignOfOp() && - Exp->getOpcode() != UnaryOperator::OffsetOf && - !Exp->getSubExpr()->isConstantExpr(Ctx, Loc)) - return false; - - switch (Exp->getOpcode()) { - // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. - // See C99 6.6p3. - default: - if (Loc) *Loc = Exp->getOperatorLoc(); - return false; - case UnaryOperator::Extension: - return true; // FIXME: this is wrong. - case UnaryOperator::SizeOf: - case UnaryOperator::AlignOf: - case UnaryOperator::OffsetOf: - // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. - if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { - if (Loc) *Loc = Exp->getOperatorLoc(); - return false; - } - return true; - case UnaryOperator::LNot: - case UnaryOperator::Plus: - case UnaryOperator::Minus: - case UnaryOperator::Not: - return true; - } - } - case SizeOfAlignOfTypeExprClass: { - const SizeOfAlignOfTypeExpr *Exp = cast(this); - // alignof always evaluates to a constant. - if (Exp->isSizeOf() && !Exp->getArgumentType()->isVoidType() && - !Exp->getArgumentType()->isConstantSizeType()) { - if (Loc) *Loc = Exp->getOperatorLoc(); - return false; - } - return true; - } - case BinaryOperatorClass: { - const BinaryOperator *Exp = cast(this); - - // The LHS of a constant expr is always evaluated and needed. - if (!Exp->getLHS()->isConstantExpr(Ctx, Loc)) - return false; - - if (!Exp->getRHS()->isConstantExpr(Ctx, Loc)) - return false; - return true; - } - case ImplicitCastExprClass: - case CastExprClass: { - const Expr *SubExpr; - SourceLocation CastLoc; - if (const CastExpr *C = dyn_cast(this)) { - SubExpr = C->getSubExpr(); - CastLoc = C->getLParenLoc(); - } else { - SubExpr = cast(this)->getSubExpr(); - CastLoc = getLocStart(); - } - if (!SubExpr->isConstantExpr(Ctx, Loc)) { - if (Loc) *Loc = SubExpr->getLocStart(); - return false; - } - return true; - } - case ConditionalOperatorClass: { - const ConditionalOperator *Exp = cast(this); - if (!Exp->getCond()->isConstantExpr(Ctx, Loc) || - // Handle the GNU extension for missing LHS. - !(Exp->getLHS() && Exp->getLHS()->isConstantExpr(Ctx, Loc)) || - !Exp->getRHS()->isConstantExpr(Ctx, Loc)) - return false; - return true; - } - case InitListExprClass: { - const InitListExpr *Exp = cast(this); - unsigned numInits = Exp->getNumInits(); - for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantExpr(Ctx, Loc)) { - if (Loc) *Loc = Exp->getInit(i)->getLocStart(); - return false; - } - } - return true; - } - } -} - -/// isIntegerConstantExpr - this recursive routine will test if an expression is -/// an integer constant expression. Note: With the introduction of VLA's in -/// C99 the result of the sizeof operator is no longer always a constant -/// expression. The generalization of the wording to include any subexpression -/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions -/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance, -/// "0 || f()" can be treated as a constant expression. In C90 this expression, -/// occurring in a context requiring a constant, would have been a constraint -/// violation. FIXME: This routine currently implements C90 semantics. -/// To properly implement C99 semantics this routine will need to evaluate -/// expressions involving operators previously mentioned. - -/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, -/// comma, etc -/// -/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not -/// permit this. This includes things like (int)1e1000 -/// -/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof -/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer -/// cast+dereference. -bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, - SourceLocation *Loc, bool isEvaluated) const { - switch (getStmtClass()) { - default: - if (Loc) *Loc = getLocStart(); - return false; - case ParenExprClass: - return cast(this)->getSubExpr()-> - isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated); - case IntegerLiteralClass: - Result = cast(this)->getValue(); - break; - case CharacterLiteralClass: { - const CharacterLiteral *CL = cast(this); - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - Result = CL->getValue(); - Result.setIsUnsigned(!getType()->isSignedIntegerType()); - break; - } - case TypesCompatibleExprClass: { - const TypesCompatibleExpr *TCE = cast(this); - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - Result = Ctx.typesAreCompatible(TCE->getArgType1(), TCE->getArgType2()); - break; - } - case CallExprClass: { - const CallExpr *CE = cast(this); - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - if (CE->isBuiltinClassifyType(Result)) - break; - if (Loc) *Loc = getLocStart(); - return false; - } - case DeclRefExprClass: - if (const EnumConstantDecl *D = - dyn_cast(cast(this)->getDecl())) { - Result = D->getInitVal(); - break; - } - if (Loc) *Loc = getLocStart(); - return false; - case UnaryOperatorClass: { - const UnaryOperator *Exp = cast(this); - - // Get the operand value. If this is sizeof/alignof, do not evalute the - // operand. This affects C99 6.6p3. - if (!Exp->isSizeOfAlignOfOp() && !Exp->isOffsetOfOp() && - !Exp->getSubExpr()->isIntegerConstantExpr(Result, Ctx, Loc,isEvaluated)) - return false; - - switch (Exp->getOpcode()) { - // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. - // See C99 6.6p3. - default: - if (Loc) *Loc = Exp->getOperatorLoc(); - return false; - case UnaryOperator::Extension: - return true; // FIXME: this is wrong. - case UnaryOperator::SizeOf: - case UnaryOperator::AlignOf: - // Return the result in the right width. - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - - // sizeof(void) and __alignof__(void) = 1 as a gcc extension. - if (Exp->getSubExpr()->getType()->isVoidType()) { - Result = 1; - break; - } - - // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. - if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { - if (Loc) *Loc = Exp->getOperatorLoc(); - return false; - } - - // Get information about the size or align. - if (Exp->getSubExpr()->getType()->isFunctionType()) { - // GCC extension: sizeof(function) = 1. - Result = Exp->getOpcode() == UnaryOperator::AlignOf ? 4 : 1; - } else { - unsigned CharSize = Ctx.Target.getCharWidth(); - if (Exp->getOpcode() == UnaryOperator::AlignOf) - Result = Ctx.getTypeAlign(Exp->getSubExpr()->getType()) / CharSize; - else - Result = Ctx.getTypeSize(Exp->getSubExpr()->getType()) / CharSize; - } - break; - case UnaryOperator::LNot: { - bool Val = Result == 0; - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - Result = Val; - break; - } - case UnaryOperator::Plus: - break; - case UnaryOperator::Minus: - Result = -Result; - break; - case UnaryOperator::Not: - Result = ~Result; - break; - case UnaryOperator::OffsetOf: - Result = Exp->evaluateOffsetOf(Ctx); - } - break; - } - case SizeOfAlignOfTypeExprClass: { - const SizeOfAlignOfTypeExpr *Exp = cast(this); - - // Return the result in the right width. - Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - - // sizeof(void) and __alignof__(void) = 1 as a gcc extension. - if (Exp->getArgumentType()->isVoidType()) { - Result = 1; - break; - } - - // alignof always evaluates to a constant, sizeof does if arg is not VLA. - if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) { - if (Loc) *Loc = Exp->getOperatorLoc(); - return false; - } - - // Get information about the size or align. - if (Exp->getArgumentType()->isFunctionType()) { - // GCC extension: sizeof(function) = 1. - Result = Exp->isSizeOf() ? 1 : 4; - } else { - unsigned CharSize = Ctx.Target.getCharWidth(); - if (Exp->isSizeOf()) - Result = Ctx.getTypeSize(Exp->getArgumentType()) / CharSize; - else - Result = Ctx.getTypeAlign(Exp->getArgumentType()) / CharSize; - } - break; - } - case BinaryOperatorClass: { - const BinaryOperator *Exp = cast(this); - - // The LHS of a constant expr is always evaluated and needed. - if (!Exp->getLHS()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) - return false; - - llvm::APSInt RHS(Result); - - // The short-circuiting &&/|| operators don't necessarily evaluate their - // RHS. Make sure to pass isEvaluated down correctly. - if (Exp->isLogicalOp()) { - bool RHSEval; - if (Exp->getOpcode() == BinaryOperator::LAnd) - RHSEval = Result != 0; - else { - assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical"); - RHSEval = Result == 0; - } - - if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, - isEvaluated & RHSEval)) - return false; - } else { - if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, isEvaluated)) - return false; - } - - switch (Exp->getOpcode()) { - default: - if (Loc) *Loc = getLocStart(); - return false; - case BinaryOperator::Mul: - Result *= RHS; - break; - case BinaryOperator::Div: - if (RHS == 0) { - if (!isEvaluated) break; - if (Loc) *Loc = getLocStart(); - return false; - } - Result /= RHS; - break; - case BinaryOperator::Rem: - if (RHS == 0) { - if (!isEvaluated) break; - if (Loc) *Loc = getLocStart(); - return false; - } - Result %= RHS; - break; - case BinaryOperator::Add: Result += RHS; break; - case BinaryOperator::Sub: Result -= RHS; break; - case BinaryOperator::Shl: - Result <<= - static_cast(RHS.getLimitedValue(Result.getBitWidth()-1)); - break; - case BinaryOperator::Shr: - Result >>= - static_cast(RHS.getLimitedValue(Result.getBitWidth()-1)); - break; - case BinaryOperator::LT: Result = Result < RHS; break; - case BinaryOperator::GT: Result = Result > RHS; break; - case BinaryOperator::LE: Result = Result <= RHS; break; - case BinaryOperator::GE: Result = Result >= RHS; break; - case BinaryOperator::EQ: Result = Result == RHS; break; - case BinaryOperator::NE: Result = Result != RHS; break; - case BinaryOperator::And: Result &= RHS; break; - case BinaryOperator::Xor: Result ^= RHS; break; - case BinaryOperator::Or: Result |= RHS; break; - case BinaryOperator::LAnd: - Result = Result != 0 && RHS != 0; - break; - case BinaryOperator::LOr: - Result = Result != 0 || RHS != 0; - break; - - case BinaryOperator::Comma: - // C99 6.6p3: "shall not contain assignment, ..., or comma operators, - // *except* when they are contained within a subexpression that is not - // evaluated". Note that Assignment can never happen due to constraints - // on the LHS subexpr, so we don't need to check it here. - if (isEvaluated) { - if (Loc) *Loc = getLocStart(); - return false; - } - - // The result of the constant expr is the RHS. - Result = RHS; - return true; - } - - assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!"); - break; - } - case ImplicitCastExprClass: - case CastExprClass: { - const Expr *SubExpr; - SourceLocation CastLoc; - if (const CastExpr *C = dyn_cast(this)) { - SubExpr = C->getSubExpr(); - CastLoc = C->getLParenLoc(); - } else { - SubExpr = cast(this)->getSubExpr(); - CastLoc = getLocStart(); - } - - // C99 6.6p6: shall only convert arithmetic types to integer types. - if (!SubExpr->getType()->isArithmeticType() || - !getType()->isIntegerType()) { - if (Loc) *Loc = SubExpr->getLocStart(); - return false; - } - - uint32_t DestWidth = static_cast(Ctx.getTypeSize(getType())); - - // Handle simple integer->integer casts. - if (SubExpr->getType()->isIntegerType()) { - if (!SubExpr->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) - return false; - - // Figure out if this is a truncate, extend or noop cast. - // If the input is signed, do a sign extend, noop, or truncate. - if (getType()->isBooleanType()) { - // Conversion to bool compares against zero. - Result = Result != 0; - Result.zextOrTrunc(DestWidth); - } else if (SubExpr->getType()->isSignedIntegerType()) - Result.sextOrTrunc(DestWidth); - else // If the input is unsigned, do a zero extend, noop, or truncate. - Result.zextOrTrunc(DestWidth); - break; - } - - // Allow floating constants that are the immediate operands of casts or that - // are parenthesized. - const Expr *Operand = SubExpr; - while (const ParenExpr *PE = dyn_cast(Operand)) - Operand = PE->getSubExpr(); - - // If this isn't a floating literal, we can't handle it. - const FloatingLiteral *FL = dyn_cast(Operand); - if (!FL) { - if (Loc) *Loc = Operand->getLocStart(); - return false; - } - - // If the destination is boolean, compare against zero. - if (getType()->isBooleanType()) { - Result = !FL->getValue().isZero(); - Result.zextOrTrunc(DestWidth); - break; - } - - // Determine whether we are converting to unsigned or signed. - bool DestSigned = getType()->isSignedIntegerType(); - - // TODO: Warn on overflow, but probably not here: isIntegerConstantExpr can - // be called multiple times per AST. - uint64_t Space[4]; - (void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned, - llvm::APFloat::rmTowardZero); - Result = llvm::APInt(DestWidth, 4, Space); - break; - } - case ConditionalOperatorClass: { - const ConditionalOperator *Exp = cast(this); - - if (!Exp->getCond()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) - return false; - - const Expr *TrueExp = Exp->getLHS(); - const Expr *FalseExp = Exp->getRHS(); - if (Result == 0) std::swap(TrueExp, FalseExp); - - // Evaluate the false one first, discard the result. - if (FalseExp && !FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false)) - return false; - // Evalute the true one, capture the result. - if (TrueExp && - !TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) - return false; - break; - } - } - - // Cases that are valid constant exprs fall through to here. - Result.setIsUnsigned(getType()->isUnsignedIntegerType()); - return true; -} - -/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an -/// integer constant expression with the value zero, or if this is one that is -/// cast to void*. -bool Expr::isNullPointerConstant(ASTContext &Ctx) const { - // Strip off a cast to void*, if it exists. - if (const CastExpr *CE = dyn_cast(this)) { - // Check that it is a cast to void*. - if (const PointerType *PT = CE->getType()->getAsPointerType()) { - QualType Pointee = PT->getPointeeType(); - if (Pointee.getCVRQualifiers() == 0 && - Pointee->isVoidType() && // to void* - CE->getSubExpr()->getType()->isIntegerType()) // from int. - return CE->getSubExpr()->isNullPointerConstant(Ctx); - } - } else if (const ImplicitCastExpr *ICE = dyn_cast(this)) { - // Ignore the ImplicitCastExpr type entirely. - return ICE->getSubExpr()->isNullPointerConstant(Ctx); - } else if (const ParenExpr *PE = dyn_cast(this)) { - // Accept ((void*)0) as a null pointer constant, as many other - // implementations do. - return PE->getSubExpr()->isNullPointerConstant(Ctx); - } - - // This expression must be an integer type. - if (!getType()->isIntegerType()) - return false; - - // If we have an integer constant expression, we need to *evaluate* it and - // test for the value 0. - llvm::APSInt Val(32); - return isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0; -} - -unsigned OCUVectorElementExpr::getNumElements() const { - return strlen(Accessor.getName()); -} - - -/// getComponentType - Determine whether the components of this access are -/// "point" "color" or "texture" elements. -OCUVectorElementExpr::ElementType -OCUVectorElementExpr::getElementType() const { - // derive the component type, no need to waste space. - const char *compStr = Accessor.getName(); - - if (OCUVectorType::getPointAccessorIdx(*compStr) != -1) return Point; - if (OCUVectorType::getColorAccessorIdx(*compStr) != -1) return Color; - - assert(OCUVectorType::getTextureAccessorIdx(*compStr) != -1 && - "getComponentType(): Illegal accessor"); - return Texture; -} - -/// containsDuplicateElements - Return true if any element access is -/// repeated. -bool OCUVectorElementExpr::containsDuplicateElements() const { - const char *compStr = Accessor.getName(); - unsigned length = strlen(compStr); - - for (unsigned i = 0; i < length-1; i++) { - const char *s = compStr+i; - for (const char c = *s++; *s; s++) - if (c == *s) - return true; - } - return false; -} - -/// getEncodedElementAccess - We encode fields with two bits per component. -unsigned OCUVectorElementExpr::getEncodedElementAccess() const { - const char *compStr = Accessor.getName(); - unsigned length = getNumElements(); - - unsigned Result = 0; - - while (length--) { - Result <<= 2; - int Idx = OCUVectorType::getAccessorIdx(compStr[length]); - assert(Idx != -1 && "Invalid accessor letter"); - Result |= Idx; - } - return Result; -} - -// constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), - MethodProto(mproto), ClassName(0) { - NumArgs = nargs; - SubExprs = new Expr*[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(IdentifierInfo *clsName, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), - MethodProto(mproto), ClassName(clsName) { - NumArgs = nargs; - SubExprs = new Expr*[NumArgs+1]; - SubExprs[RECEIVER] = 0; - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - - -bool ChooseExpr::isConditionTrue(ASTContext &C) const { - llvm::APSInt CondVal(32); - bool IsConst = getCond()->isIntegerConstantExpr(CondVal, C); - assert(IsConst && "Condition of choose expr must be i-c-e"); IsConst=IsConst; - return CondVal != 0; -} - -static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E) -{ - if (const MemberExpr *ME = dyn_cast(E)) { - QualType Ty = ME->getBase()->getType(); - - RecordDecl *RD = Ty->getAsRecordType()->getDecl(); - const ASTRecordLayout &RL = C.getASTRecordLayout(RD); - FieldDecl *FD = ME->getMemberDecl(); - - // FIXME: This is linear time. - unsigned i = 0, e = 0; - for (i = 0, e = RD->getNumMembers(); i != e; i++) { - if (RD->getMember(i) == FD) - break; - } - - return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase()); - } else if (const ArraySubscriptExpr *ASE = dyn_cast(E)) { - const Expr *Base = ASE->getBase(); - llvm::APSInt Idx(32); - bool ICE = ASE->getIdx()->isIntegerConstantExpr(Idx, C); - assert(ICE && "Array index is not a constant integer!"); - - int64_t size = C.getTypeSize(ASE->getType()); - size *= Idx.getSExtValue(); - - return size + evaluateOffsetOf(C, Base); - } else if (isa(E)) - return 0; - - assert(0 && "Unknown offsetof subexpression!"); - return 0; -} - -int64_t UnaryOperator::evaluateOffsetOf(ASTContext& C) const -{ - assert(Opc == OffsetOf && "Unary operator not offsetof!"); - - unsigned CharSize = C.Target.getCharWidth(); - return ::evaluateOffsetOf(C, Val) / CharSize; -} - -//===----------------------------------------------------------------------===// -// Child Iterators for iterating over subexpressions/substatements -//===----------------------------------------------------------------------===// - -// DeclRefExpr -Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); } - -// ObjCIvarRefExpr -Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator ObjCIvarRefExpr::child_end() { return child_iterator(); } - -// PreDefinedExpr -Stmt::child_iterator PreDefinedExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator PreDefinedExpr::child_end() { return child_iterator(); } - -// IntegerLiteral -Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); } - -// CharacterLiteral -Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); } - -// FloatingLiteral -Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); } - -// ImaginaryLiteral -Stmt::child_iterator ImaginaryLiteral::child_begin() { - return reinterpret_cast(&Val); -} -Stmt::child_iterator ImaginaryLiteral::child_end() { - return reinterpret_cast(&Val)+1; -} - -// StringLiteral -Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); } - -// ParenExpr -Stmt::child_iterator ParenExpr::child_begin() { - return reinterpret_cast(&Val); -} -Stmt::child_iterator ParenExpr::child_end() { - return reinterpret_cast(&Val)+1; -} - -// UnaryOperator -Stmt::child_iterator UnaryOperator::child_begin() { - return reinterpret_cast(&Val); -} -Stmt::child_iterator UnaryOperator::child_end() { - return reinterpret_cast(&Val+1); -} - -// SizeOfAlignOfTypeExpr -Stmt::child_iterator SizeOfAlignOfTypeExpr::child_begin() { - // If the type is a VLA type (and not a typedef), the size expression of the - // VLA needs to be treated as an executable expression. - if (VariableArrayType* T = dyn_cast(Ty.getTypePtr())) - return child_iterator(T); - else - return child_iterator(); -} -Stmt::child_iterator SizeOfAlignOfTypeExpr::child_end() { - return child_iterator(); -} - -// ArraySubscriptExpr -Stmt::child_iterator ArraySubscriptExpr::child_begin() { - return reinterpret_cast(&SubExprs); -} -Stmt::child_iterator ArraySubscriptExpr::child_end() { - return reinterpret_cast(&SubExprs)+END_EXPR; -} - -// CallExpr -Stmt::child_iterator CallExpr::child_begin() { - return reinterpret_cast(&SubExprs[0]); -} -Stmt::child_iterator CallExpr::child_end() { - return reinterpret_cast(&SubExprs[NumArgs+ARGS_START]); -} - -// MemberExpr -Stmt::child_iterator MemberExpr::child_begin() { - return reinterpret_cast(&Base); -} -Stmt::child_iterator MemberExpr::child_end() { - return reinterpret_cast(&Base)+1; -} - -// OCUVectorElementExpr -Stmt::child_iterator OCUVectorElementExpr::child_begin() { - return reinterpret_cast(&Base); -} -Stmt::child_iterator OCUVectorElementExpr::child_end() { - return reinterpret_cast(&Base)+1; -} - -// CompoundLiteralExpr -Stmt::child_iterator CompoundLiteralExpr::child_begin() { - return reinterpret_cast(&Init); -} -Stmt::child_iterator CompoundLiteralExpr::child_end() { - return reinterpret_cast(&Init)+1; -} - -// ImplicitCastExpr -Stmt::child_iterator ImplicitCastExpr::child_begin() { - return reinterpret_cast(&Op); -} -Stmt::child_iterator ImplicitCastExpr::child_end() { - return reinterpret_cast(&Op)+1; -} - -// CastExpr -Stmt::child_iterator CastExpr::child_begin() { - return reinterpret_cast(&Op); -} -Stmt::child_iterator CastExpr::child_end() { - return reinterpret_cast(&Op)+1; -} - -// BinaryOperator -Stmt::child_iterator BinaryOperator::child_begin() { - return reinterpret_cast(&SubExprs); -} -Stmt::child_iterator BinaryOperator::child_end() { - return reinterpret_cast(&SubExprs)+END_EXPR; -} - -// ConditionalOperator -Stmt::child_iterator ConditionalOperator::child_begin() { - return reinterpret_cast(&SubExprs); -} -Stmt::child_iterator ConditionalOperator::child_end() { - return reinterpret_cast(&SubExprs)+END_EXPR; -} - -// AddrLabelExpr -Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); } - -// StmtExpr -Stmt::child_iterator StmtExpr::child_begin() { - return reinterpret_cast(&SubStmt); -} -Stmt::child_iterator StmtExpr::child_end() { - return reinterpret_cast(&SubStmt)+1; -} - -// TypesCompatibleExpr -Stmt::child_iterator TypesCompatibleExpr::child_begin() { - return child_iterator(); -} - -Stmt::child_iterator TypesCompatibleExpr::child_end() { - return child_iterator(); -} - -// ChooseExpr -Stmt::child_iterator ChooseExpr::child_begin() { - return reinterpret_cast(&SubExprs); -} - -Stmt::child_iterator ChooseExpr::child_end() { - return reinterpret_cast(&SubExprs)+END_EXPR; -} - -// OverloadExpr -Stmt::child_iterator OverloadExpr::child_begin() { - return reinterpret_cast(&SubExprs[0]); -} -Stmt::child_iterator OverloadExpr::child_end() { - return reinterpret_cast(&SubExprs[NumExprs]); -} - -// VAArgExpr -Stmt::child_iterator VAArgExpr::child_begin() { - return reinterpret_cast(&Val); -} - -Stmt::child_iterator VAArgExpr::child_end() { - return reinterpret_cast(&Val)+1; -} - -// InitListExpr -Stmt::child_iterator InitListExpr::child_begin() { - return reinterpret_cast(&InitExprs[0]); -} -Stmt::child_iterator InitListExpr::child_end() { - return reinterpret_cast(&InitExprs[NumInits]); -} - -// ObjCStringLiteral -Stmt::child_iterator ObjCStringLiteral::child_begin() { - return child_iterator(); -} -Stmt::child_iterator ObjCStringLiteral::child_end() { - return child_iterator(); -} - -// ObjCEncodeExpr -Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } - -// ObjCSelectorExpr -Stmt::child_iterator ObjCSelectorExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator ObjCSelectorExpr::child_end() { - return child_iterator(); -} - -// ObjCProtocolExpr -Stmt::child_iterator ObjCProtocolExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator ObjCProtocolExpr::child_end() { - return child_iterator(); -} - -// ObjCMessageExpr -Stmt::child_iterator ObjCMessageExpr::child_begin() { - return reinterpret_cast(&SubExprs[0]); -} -Stmt::child_iterator ObjCMessageExpr::child_end() { - return reinterpret_cast(&SubExprs[getNumArgs()+ARGS_START]); -} - diff --git a/clang/AST/ExprCXX.cpp b/clang/AST/ExprCXX.cpp deleted file mode 100644 index 3bc32e75d87..00000000000 --- a/clang/AST/ExprCXX.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the subclesses of Expr class declared in ExprCXX.h -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ExprCXX.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Child Iterators for iterating over subexpressions/substatements -//===----------------------------------------------------------------------===// - - -// CXXCastExpr -Stmt::child_iterator CXXCastExpr::child_begin() { - return reinterpret_cast(&Op); -} -Stmt::child_iterator CXXCastExpr::child_end() { - return reinterpret_cast(&Op)+1; -} - -// CXXBoolLiteralExpr -Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator CXXBoolLiteralExpr::child_end() { - return child_iterator(); -} - -// CXXThrowExpr -Stmt::child_iterator CXXThrowExpr::child_begin() { - return reinterpret_cast(&Op); -} -Stmt::child_iterator CXXThrowExpr::child_end() { - // If Op is 0, we are processing throw; which has no children. - if (Op == 0) - return reinterpret_cast(&Op)+0; - return reinterpret_cast(&Op)+1; -} diff --git a/clang/AST/Makefile b/clang/AST/Makefile deleted file mode 100644 index 066fdb6a429..00000000000 --- a/clang/AST/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -##===- clang/AST/Makefile ----------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the AST library for the C-Language front-end. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangAST -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/AST/Stmt.cpp b/clang/AST/Stmt.cpp deleted file mode 100644 index 572280bc054..00000000000 --- a/clang/AST/Stmt.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Stmt class and statement subclasses. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Stmt.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Basic/IdentifierTable.h" -using namespace clang; - -static struct StmtClassNameTable { - const char *Name; - unsigned Counter; - unsigned Size; -} StmtClassInfo[Stmt::lastExprConstant+1]; - -static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { - static bool Initialized = false; - if (Initialized) - return StmtClassInfo[E]; - - // Intialize the table on the first use. - Initialized = true; -#define STMT(N, CLASS, PARENT) \ - StmtClassInfo[N].Name = #CLASS; \ - StmtClassInfo[N].Size = sizeof(CLASS); -#include "clang/AST/StmtNodes.def" - - return StmtClassInfo[E]; -} - -const char *Stmt::getStmtClassName() const { - return getStmtInfoTableEntry(sClass).Name; -} - -void Stmt::PrintStats() { - // Ensure the table is primed. - getStmtInfoTableEntry(Stmt::NullStmtClass); - - unsigned sum = 0; - fprintf(stderr, "*** Stmt/Expr Stats:\n"); - for (int i = 0; i != Stmt::lastExprConstant+1; i++) { - if (StmtClassInfo[i].Name == 0) continue; - sum += StmtClassInfo[i].Counter; - } - fprintf(stderr, " %d stmts/exprs total.\n", sum); - sum = 0; - for (int i = 0; i != Stmt::lastExprConstant+1; i++) { - if (StmtClassInfo[i].Name == 0) continue; - fprintf(stderr, " %d %s, %d each (%d bytes)\n", - StmtClassInfo[i].Counter, StmtClassInfo[i].Name, - StmtClassInfo[i].Size, - StmtClassInfo[i].Counter*StmtClassInfo[i].Size); - sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size; - } - fprintf(stderr, "Total bytes = %d\n", sum); -} - -void Stmt::addStmtClass(StmtClass s) { - ++getStmtInfoTableEntry(s).Counter; -} - -static bool StatSwitch = false; - -bool Stmt::CollectingStats(bool enable) { - if (enable) StatSwitch = true; - return StatSwitch; -} - - -const char *LabelStmt::getName() const { - return getID()->getName(); -} - -// This is defined here to avoid polluting Stmt.h with importing Expr.h -SourceRange ReturnStmt::getSourceRange() const { - if (RetExpr) - return SourceRange(RetLoc, RetExpr->getLocEnd()); - else - return SourceRange(RetLoc); -} - -bool Stmt::hasImplicitControlFlow() const { - switch (sClass) { - default: - return false; - - case CallExprClass: - case ConditionalOperatorClass: - case ChooseExprClass: - case StmtExprClass: - case DeclStmtClass: - return true; - - case Stmt::BinaryOperatorClass: { - const BinaryOperator* B = cast(this); - if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma) - return true; - else - return false; - } - } -} - -//===----------------------------------------------------------------------===// -// Constructors -//===----------------------------------------------------------------------===// - -AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, - unsigned numoutputs, unsigned numinputs, - std::string *names, StringLiteral **constraints, - Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, - StringLiteral **clobbers, SourceLocation rparenloc) - : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) - , IsSimple(issimple), IsVolatile(isvolatile) - , NumOutputs(numoutputs), NumInputs(numinputs) { - for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) { - Names.push_back(names[i]); - Exprs.push_back(exprs[i]); - Constraints.push_back(constraints[i]); - } - - for (unsigned i = 0; i != numclobbers; i++) - Clobbers.push_back(clobbers[i]); -} - -ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, - Stmt *Body, SourceLocation FCL, - SourceLocation RPL) -: Stmt(ObjCForCollectionStmtClass) { - SubExprs[ELEM] = Elem; - SubExprs[COLLECTION] = reinterpret_cast(Collect); - SubExprs[BODY] = Body; - ForLoc = FCL; - RParenLoc = RPL; -} - - -ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, - SourceLocation rparenloc, - Stmt *catchVarStmtDecl, Stmt *atCatchStmt, - Stmt *atCatchList) -: Stmt(ObjCAtCatchStmtClass) { - SubExprs[SELECTOR] = catchVarStmtDecl; - SubExprs[BODY] = atCatchStmt; - if (!atCatchList) - SubExprs[NEXT_CATCH] = NULL; - else { - ObjCAtCatchStmt *AtCatchList = static_cast(atCatchList); - - while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) - AtCatchList = NextCatch; - - AtCatchList->SubExprs[NEXT_CATCH] = this; - } - AtCatchLoc = atCatchLoc; - RParenLoc = rparenloc; -} - - -//===----------------------------------------------------------------------===// -// Child Iterators for iterating over subexpressions/substatements -//===----------------------------------------------------------------------===// - -// DeclStmt -Stmt::child_iterator DeclStmt::child_begin() { return getDecl(); } -Stmt::child_iterator DeclStmt::child_end() { return child_iterator(); } - -// NullStmt -Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator NullStmt::child_end() { return child_iterator(); } - -// CompoundStmt -Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; } -Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); } - -// CaseStmt -Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; } - -// DefaultStmt -Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; } -Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; } - -// LabelStmt -Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } -Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } - -// IfStmt -Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; } - -// SwitchStmt -Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; } - -// WhileStmt -Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; } - -// DoStmt -Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } - -// ForStmt -Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; } - -// ObjCForCollectionStmt -Stmt::child_iterator ObjCForCollectionStmt::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator ObjCForCollectionStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// GotoStmt -Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } - -// IndirectGotoStmt -Stmt::child_iterator IndirectGotoStmt::child_begin() { - return reinterpret_cast(&Target); -} - -Stmt::child_iterator IndirectGotoStmt::child_end() { return ++child_begin(); } - -// ContinueStmt -Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); } - -// BreakStmt -Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); } - -// ReturnStmt -Stmt::child_iterator ReturnStmt::child_begin() { - if (RetExpr) return reinterpret_cast(&RetExpr); - else return child_iterator(); -} - -Stmt::child_iterator ReturnStmt::child_end() { - if (RetExpr) return reinterpret_cast(&RetExpr)+1; - else return child_iterator(); -} - -// AsmStmt -Stmt::child_iterator AsmStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator AsmStmt::child_end() { return child_iterator(); } - -// ObjCAtCatchStmt -Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ObjCAtCatchStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// 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; -} - -// ObjCAtThrowStmt -Stmt::child_iterator ObjCAtThrowStmt::child_begin() { - return &Throw; -} - -Stmt::child_iterator ObjCAtThrowStmt::child_end() { - return &Throw+1; -} - -// ObjCAtSynchronizedStmt -Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() { - return &SubStmts[0]; -} - -Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() { - return &SubStmts[0]+END_EXPR; -} - diff --git a/clang/AST/StmtDumper.cpp b/clang/AST/StmtDumper.cpp deleted file mode 100644 index d813899b530..00000000000 --- a/clang/AST/StmtDumper.cpp +++ /dev/null @@ -1,486 +0,0 @@ -//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Stmt::dump/Stmt::print methods, which dump out the -// AST in a form that exposes type details and other fields. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/ExprCXX.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" -#include -using namespace clang; - -//===----------------------------------------------------------------------===// -// StmtDumper Visitor -//===----------------------------------------------------------------------===// - -namespace { - class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor { - SourceManager *SM; - FILE *F; - unsigned IndentLevel; - - /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump - /// the first few levels of an AST. This keeps track of how many ast levels - /// are left. - unsigned MaxDepth; - - /// LastLocFilename/LastLocLine - Keep track of the last location we print - /// out so that we can print out deltas from then on out. - const char *LastLocFilename; - unsigned LastLocLine; - public: - StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth) - : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) { - LastLocFilename = ""; - LastLocLine = ~0U; - } - - void DumpSubTree(Stmt *S) { - // Prune the recursion if not using dump all. - if (MaxDepth == 0) return; - - ++IndentLevel; - if (S) { - if (DeclStmt* DS = dyn_cast(S)) - VisitDeclStmt(DS); - else { - Visit(S); - - // Print out children. - Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); - if (CI != CE) { - while (CI != CE) { - fprintf(F, "\n"); - DumpSubTree(*CI++); - } - } - fprintf(F, ")"); - } - } else { - Indent(); - fprintf(F, "<<>>"); - } - --IndentLevel; - } - - void DumpDeclarator(Decl *D); - - void Indent() const { - for (int i = 0, e = IndentLevel; i < e; ++i) - fprintf(F, " "); - } - - void DumpType(QualType T) { - fprintf(F, "'%s'", T.getAsString().c_str()); - - // If the type is directly a typedef, strip off typedefness to give at - // least one level of concreteness. - if (TypedefType *TDT = dyn_cast(T)) - fprintf(F, ":'%s'", TDT->LookThroughTypedefs().getAsString().c_str()); - } - void DumpStmt(const Stmt *Node) { - Indent(); - fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node); - DumpSourceRange(Node); - } - void DumpExpr(const Expr *Node) { - DumpStmt(Node); - fprintf(F, " "); - DumpType(Node->getType()); - } - void DumpSourceRange(const Stmt *Node); - void DumpLocation(SourceLocation Loc); - - // Stmts. - void VisitStmt(Stmt *Node); - void VisitDeclStmt(DeclStmt *Node); - void VisitLabelStmt(LabelStmt *Node); - void VisitGotoStmt(GotoStmt *Node); - - // Exprs - void VisitExpr(Expr *Node); - void VisitDeclRefExpr(DeclRefExpr *Node); - void VisitPreDefinedExpr(PreDefinedExpr *Node); - void VisitCharacterLiteral(CharacterLiteral *Node); - void VisitIntegerLiteral(IntegerLiteral *Node); - void VisitFloatingLiteral(FloatingLiteral *Node); - void VisitStringLiteral(StringLiteral *Str); - void VisitUnaryOperator(UnaryOperator *Node); - void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node); - void VisitMemberExpr(MemberExpr *Node); - void VisitOCUVectorElementExpr(OCUVectorElementExpr *Node); - void VisitBinaryOperator(BinaryOperator *Node); - void VisitCompoundAssignOperator(CompoundAssignOperator *Node); - void VisitAddrLabelExpr(AddrLabelExpr *Node); - void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); - - // C++ - void VisitCXXCastExpr(CXXCastExpr *Node); - void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); - - // ObjC - void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); - void VisitObjCMessageExpr(ObjCMessageExpr* Node); - void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); - void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); - }; -} - -//===----------------------------------------------------------------------===// -// Utilities -//===----------------------------------------------------------------------===// - -void StmtDumper::DumpLocation(SourceLocation Loc) { - SourceLocation PhysLoc = SM->getPhysicalLoc(Loc); - - // The general format we print out is filename:line:col, but we drop pieces - // that haven't changed since the last loc printed. - const char *Filename = SM->getSourceName(PhysLoc); - unsigned LineNo = SM->getLineNumber(PhysLoc); - if (strcmp(Filename, LastLocFilename) != 0) { - fprintf(stderr, "%s:%u:%u", Filename, LineNo, SM->getColumnNumber(PhysLoc)); - LastLocFilename = Filename; - LastLocLine = LineNo; - } else if (LineNo != LastLocLine) { - fprintf(stderr, "line:%u:%u", LineNo, SM->getColumnNumber(PhysLoc)); - LastLocLine = LineNo; - } else { - fprintf(stderr, "col:%u", SM->getColumnNumber(PhysLoc)); - } -} - -void StmtDumper::DumpSourceRange(const Stmt *Node) { - // Can't translate locations if a SourceManager isn't available. - if (SM == 0) return; - - // TODO: If the parent expression is available, we can print a delta vs its - // location. - SourceRange R = Node->getSourceRange(); - - fprintf(stderr, " <"); - DumpLocation(R.getBegin()); - if (R.getBegin() != R.getEnd()) { - fprintf(stderr, ", "); - DumpLocation(R.getEnd()); - } - fprintf(stderr, ">"); - - // - -} - - -//===----------------------------------------------------------------------===// -// Stmt printing methods. -//===----------------------------------------------------------------------===// - -void StmtDumper::VisitStmt(Stmt *Node) { - DumpStmt(Node); -} - -void StmtDumper::DumpDeclarator(Decl *D) { - // FIXME: Need to complete/beautify this... this code simply shows the - // nodes are where they need to be. - if (TypedefDecl *localType = dyn_cast(D)) { - fprintf(F, "\"typedef %s %s\"", - localType->getUnderlyingType().getAsString().c_str(), - localType->getName()); - } else if (ValueDecl *VD = dyn_cast(D)) { - fprintf(F, "\""); - // Emit storage class for vardecls. - if (VarDecl *V = dyn_cast(VD)) { - switch (V->getStorageClass()) { - default: assert(0 && "Unknown storage class!"); - case VarDecl::None: break; - case VarDecl::Extern: fprintf(F, "extern "); break; - case VarDecl::Static: fprintf(F, "static "); break; - case VarDecl::Auto: fprintf(F, "auto "); break; - case VarDecl::Register: fprintf(F, "register "); break; - } - } - - std::string Name = VD->getName(); - VD->getType().getAsStringInternal(Name); - fprintf(F, "%s", Name.c_str()); - - // If this is a vardecl with an initializer, emit it. - if (VarDecl *V = dyn_cast(VD)) { - if (V->getInit()) { - fprintf(F, " =\n"); - DumpSubTree(V->getInit()); - } - } - fprintf(F, "\""); - } else if (TagDecl *TD = dyn_cast(D)) { - // print a free standing tag decl (e.g. "struct x;"). - const char *tagname; - if (const IdentifierInfo *II = TD->getIdentifier()) - tagname = II->getName(); - else - tagname = ""; - fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); - // FIXME: print tag bodies. - } else { - assert(0 && "Unexpected decl"); - } -} - -void StmtDumper::VisitDeclStmt(DeclStmt *Node) { - DumpStmt(Node); - fprintf(F,"\n"); - for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { - ++IndentLevel; - Indent(); - fprintf(F, "%p ", (void*) D); - DumpDeclarator(D); - if (D->getNextDeclarator()) - fprintf(F,"\n"); - --IndentLevel; - } -} - -void StmtDumper::VisitLabelStmt(LabelStmt *Node) { - DumpStmt(Node); - fprintf(F, " '%s'\n", Node->getName()); -} - -void StmtDumper::VisitGotoStmt(GotoStmt *Node) { - DumpStmt(Node); - fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel()); -} - -//===----------------------------------------------------------------------===// -// Expr printing methods. -//===----------------------------------------------------------------------===// - -void StmtDumper::VisitExpr(Expr *Node) { - DumpExpr(Node); -} - -void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { - DumpExpr(Node); - - fprintf(F, " "); - switch (Node->getDecl()->getKind()) { - case Decl::Function: fprintf(F,"FunctionDecl"); break; - case Decl::BlockVar: fprintf(F,"BlockVar"); break; - case Decl::FileVar: fprintf(F,"FileVar"); break; - case Decl::ParmVar: fprintf(F,"ParmVar"); break; - case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; - case Decl::Typedef: fprintf(F,"Typedef"); break; - case Decl::Struct: fprintf(F,"Struct"); break; - case Decl::Union: fprintf(F,"Union"); break; - case Decl::Class: fprintf(F,"Class"); break; - case Decl::Enum: fprintf(F,"Enum"); break; - case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; - case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; - default: fprintf(F,"Decl"); break; - } - - fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl()); -} - -void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { - DumpExpr(Node->getBase()); - - fprintf(F, " ObjCIvarRefExpr"); - fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl()); -} - -void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) { - DumpExpr(Node); - switch (Node->getIdentType()) { - default: - assert(0 && "unknown case"); - case PreDefinedExpr::Func: - fprintf(F, " __func__"); - break; - case PreDefinedExpr::Function: - fprintf(F, " __FUNCTION__"); - break; - case PreDefinedExpr::PrettyFunction: - fprintf(F, " __PRETTY_FUNCTION__"); - break; - } -} - -void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { - DumpExpr(Node); - fprintf(F, " %d", Node->getValue()); -} - -void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { - DumpExpr(Node); - - bool isSigned = Node->getType()->isSignedIntegerType(); - fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str()); -} -void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { - DumpExpr(Node); - fprintf(F, " %f", Node->getValueAsDouble()); -} - -void StmtDumper::VisitStringLiteral(StringLiteral *Str) { - DumpExpr(Str); - // FIXME: this doesn't print wstrings right. - fprintf(F, " %s\"", Str->isWide() ? "L" : ""); - - for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { - switch (char C = Str->getStrData()[i]) { - default: - if (isprint(C)) - fputc(C, F); - else - fprintf(F, "\\%03o", C); - break; - // Handle some common ones to make dumps prettier. - case '\\': fprintf(F, "\\\\"); break; - case '"': fprintf(F, "\\\""); break; - case '\n': fprintf(F, "\\n"); break; - case '\t': fprintf(F, "\\t"); break; - case '\a': fprintf(F, "\\a"); break; - case '\b': fprintf(F, "\\b"); break; - } - } - fprintf(F, "\""); -} - -void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { - DumpExpr(Node); - fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix", - UnaryOperator::getOpcodeStr(Node->getOpcode())); -} -void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { - DumpExpr(Node); - fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof"); - DumpType(Node->getArgumentType()); -} - -void StmtDumper::VisitMemberExpr(MemberExpr *Node) { - DumpExpr(Node); - fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", - Node->getMemberDecl()->getName(), (void*)Node->getMemberDecl()); -} -void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { - DumpExpr(Node); - fprintf(F, " %s", Node->getAccessor().getName()); -} -void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { - DumpExpr(Node); - fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode())); -} -void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { - DumpExpr(Node); - fprintf(F, " '%s' ComputeTy=", - BinaryOperator::getOpcodeStr(Node->getOpcode())); - DumpType(Node->getComputationType()); -} - -// GNU extensions. - -void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { - DumpExpr(Node); - fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel()); -} - -void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { - DumpExpr(Node); - fprintf(F, " "); - DumpType(Node->getArgType1()); - fprintf(F, " "); - DumpType(Node->getArgType2()); -} - -//===----------------------------------------------------------------------===// -// C++ Expressions -//===----------------------------------------------------------------------===// - -void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) { - DumpExpr(Node); - fprintf(F, " %s", CXXCastExpr::getOpcodeStr(Node->getOpcode())); -} - -void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { - DumpExpr(Node); - fprintf(F, " %s", Node->getValue() ? "true" : "false"); -} - -//===----------------------------------------------------------------------===// -// Obj-C Expressions -//===----------------------------------------------------------------------===// - -void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { - DumpExpr(Node); - fprintf(F, " selector=%s", Node->getSelector().getName().c_str()); -} - -void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { - DumpExpr(Node); - - fprintf(F, " "); - DumpType(Node->getEncodedType()); -} - -void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { - DumpExpr(Node); - - fprintf(F, " "); - Selector &selector = Node->getSelector(); - fprintf(F, "%s", selector.getName().c_str()); -} - -void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - DumpExpr(Node); - - fprintf(F, " "); - fprintf(F, "%s", Node->getProtocol()->getName()); -} -//===----------------------------------------------------------------------===// -// Stmt method implementations -//===----------------------------------------------------------------------===// - -/// dump - This does a local dump of the specified AST fragment. It dumps the -/// specified node and a few nodes underneath it, but not the whole subtree. -/// This is useful in a debugger. -void Stmt::dump(SourceManager &SM) const { - StmtDumper P(&SM, stderr, 4); - P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); -} - -/// dump - This does a local dump of the specified AST fragment. It dumps the -/// specified node and a few nodes underneath it, but not the whole subtree. -/// This is useful in a debugger. -void Stmt::dump() const { - StmtDumper P(0, stderr, 4); - P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); -} - -/// dumpAll - This does a dump of the specified AST fragment and all subtrees. -void Stmt::dumpAll(SourceManager &SM) const { - StmtDumper P(&SM, stderr, ~0U); - P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); -} - -/// dumpAll - This does a dump of the specified AST fragment and all subtrees. -void Stmt::dumpAll() const { - StmtDumper P(0, stderr, ~0U); - P.DumpSubTree(const_cast(this)); - fprintf(stderr, "\n"); -} diff --git a/clang/AST/StmtIterator.cpp b/clang/AST/StmtIterator.cpp deleted file mode 100644 index 14083e30a99..00000000000 --- a/clang/AST/StmtIterator.cpp +++ /dev/null @@ -1,118 +0,0 @@ -//===--- StmtIterator.cpp - Iterators for Statements ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines internal methods for StmtIterator. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/StmtIterator.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Decl.h" - -using namespace clang; - -static inline VariableArrayType* FindVA(Type* t) { - while (ArrayType* vt = dyn_cast(t)) { - if (VariableArrayType* vat = dyn_cast(vt)) - if (vat->getSizeExpr()) - return vat; - - t = vt->getElementType().getTypePtr(); - } - - return NULL; -} - -void StmtIteratorBase::NextVA() { - assert (getVAPtr()); - - VariableArrayType* p = getVAPtr(); - p = FindVA(p->getElementType().getTypePtr()); - setVAPtr(p); - - if (!p && decl) { - if (VarDecl* VD = dyn_cast(decl)) - if (VD->Init) - return; - - NextDecl(); - } - else { - RawVAPtr = 0; - } -} - -void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { - assert (inDecl()); - assert (getVAPtr() == NULL); - assert (decl); - - if (ImmediateAdvance) { - decl = decl->getNextDeclarator(); - - if (!decl) { - RawVAPtr = 0; - return; - } - } - - for ( ; decl ; decl = decl->getNextDeclarator()) { - if (VarDecl* VD = dyn_cast(decl)) { - if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { - setVAPtr(VAPtr); - return; - } - - if (VD->getInit()) - return; - } - else if (TypedefDecl* TD = dyn_cast(decl)) { - if (VariableArrayType* VAPtr = - FindVA(TD->getUnderlyingType().getTypePtr())) { - setVAPtr(VAPtr); - return; - } - } - else if (EnumConstantDecl* ECD = dyn_cast(decl)) - if (ECD->getInitExpr()) - return; - } - - if (!decl) { - RawVAPtr = 0; - return; - } -} - -StmtIteratorBase::StmtIteratorBase(ScopedDecl* d) - : decl(d), RawVAPtr(DeclMode) { - assert (decl); - NextDecl(false); -} - -StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) -: decl(NULL), RawVAPtr(SizeOfTypeVAMode) { - RawVAPtr |= reinterpret_cast(t); -} - - -Stmt*& StmtIteratorBase::GetDeclExpr() const { - if (VariableArrayType* VAPtr = getVAPtr()) { - assert (VAPtr->SizeExpr); - return reinterpret_cast(VAPtr->SizeExpr); - } - - if (VarDecl* VD = dyn_cast(decl)) { - assert (VD->Init); - return reinterpret_cast(VD->Init); - } - - EnumConstantDecl* ECD = cast(decl); - return reinterpret_cast(ECD->Init); -} diff --git a/clang/AST/StmtPrinter.cpp b/clang/AST/StmtPrinter.cpp deleted file mode 100644 index ba82b7fcff7..00000000000 --- a/clang/AST/StmtPrinter.cpp +++ /dev/null @@ -1,854 +0,0 @@ -//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which -// pretty print the AST back out to C code. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/PrettyPrinter.h" -#include "clang/Basic/IdentifierTable.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Streams.h" -#include -using namespace clang; - -//===----------------------------------------------------------------------===// -// StmtPrinter Visitor -//===----------------------------------------------------------------------===// - -namespace { - class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor { - std::ostream &OS; - unsigned IndentLevel; - clang::PrinterHelper* Helper; - public: - StmtPrinter(std::ostream &os, PrinterHelper* helper) : - OS(os), IndentLevel(0), Helper(helper) {} - - void PrintStmt(Stmt *S, int SubIndent = 1) { - IndentLevel += SubIndent; - if (S && isa(S)) { - // If this is an expr used in a stmt context, indent and newline it. - Indent(); - Visit(S); - OS << ";\n"; - } else if (S) { - Visit(S); - } else { - Indent() << "<<>>\n"; - } - IndentLevel -= SubIndent; - } - - void PrintRawCompoundStmt(CompoundStmt *S); - void PrintRawDecl(Decl *D); - void PrintRawIfStmt(IfStmt *If); - - void PrintExpr(Expr *E) { - if (E) - Visit(E); - else - OS << ""; - } - - std::ostream &Indent(int Delta = 0) const { - for (int i = 0, e = IndentLevel+Delta; i < e; ++i) - OS << " "; - return OS; - } - - bool PrintOffsetOfDesignator(Expr *E); - void VisitUnaryOffsetOf(UnaryOperator *Node); - - void Visit(Stmt* S) { - if (Helper && Helper->handledStmt(S,OS)) - return; - else StmtVisitor::Visit(S); - } - - void VisitStmt(Stmt *Node); -#define STMT(N, CLASS, PARENT) \ - void Visit##CLASS(CLASS *Node); -#include "clang/AST/StmtNodes.def" - }; -} - -//===----------------------------------------------------------------------===// -// Stmt printing methods. -//===----------------------------------------------------------------------===// - -void StmtPrinter::VisitStmt(Stmt *Node) { - Indent() << "<>\n"; -} - -/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and -/// with no newline after the }. -void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { - OS << "{\n"; - for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); - I != E; ++I) - PrintStmt(*I); - - Indent() << "}"; -} - -void StmtPrinter::PrintRawDecl(Decl *D) { - // FIXME: Need to complete/beautify this... this code simply shows the - // nodes are where they need to be. - if (TypedefDecl *localType = dyn_cast(D)) { - OS << "typedef " << localType->getUnderlyingType().getAsString(); - OS << " " << localType->getName(); - } else if (ValueDecl *VD = dyn_cast(D)) { - // Emit storage class for vardecls. - if (VarDecl *V = dyn_cast(VD)) { - switch (V->getStorageClass()) { - default: assert(0 && "Unknown storage class!"); - case VarDecl::None: break; - case VarDecl::Extern: OS << "extern "; break; - case VarDecl::Static: OS << "static "; break; - case VarDecl::Auto: OS << "auto "; break; - case VarDecl::Register: OS << "register "; break; - } - } - - std::string Name = VD->getName(); - VD->getType().getAsStringInternal(Name); - OS << Name; - - // If this is a vardecl with an initializer, emit it. - if (VarDecl *V = dyn_cast(VD)) { - if (V->getInit()) { - OS << " = "; - PrintExpr(V->getInit()); - } - } - } else if (TagDecl *TD = dyn_cast(D)) { - // print a free standing tag decl (e.g. "struct x;"). - OS << TD->getKindName(); - OS << " "; - if (const IdentifierInfo *II = TD->getIdentifier()) - OS << II->getName(); - else - OS << ""; - // FIXME: print tag bodies. - } else { - assert(0 && "Unexpected decl"); - } -} - - -void StmtPrinter::VisitNullStmt(NullStmt *Node) { - Indent() << ";\n"; -} - -void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { - for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { - Indent(); - PrintRawDecl(D); - OS << ";\n"; - } -} - -void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) { - Indent(); - PrintRawCompoundStmt(Node); - OS << "\n"; -} - -void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { - Indent(-1) << "case "; - PrintExpr(Node->getLHS()); - if (Node->getRHS()) { - OS << " ... "; - PrintExpr(Node->getRHS()); - } - OS << ":\n"; - - PrintStmt(Node->getSubStmt(), 0); -} - -void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) { - Indent(-1) << "default:\n"; - PrintStmt(Node->getSubStmt(), 0); -} - -void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { - Indent(-1) << Node->getName() << ":\n"; - PrintStmt(Node->getSubStmt(), 0); -} - -void StmtPrinter::PrintRawIfStmt(IfStmt *If) { - OS << "if "; - PrintExpr(If->getCond()); - - if (CompoundStmt *CS = dyn_cast(If->getThen())) { - OS << ' '; - PrintRawCompoundStmt(CS); - OS << (If->getElse() ? ' ' : '\n'); - } else { - OS << '\n'; - PrintStmt(If->getThen()); - if (If->getElse()) Indent(); - } - - if (Stmt *Else = If->getElse()) { - OS << "else"; - - if (CompoundStmt *CS = dyn_cast(Else)) { - OS << ' '; - PrintRawCompoundStmt(CS); - OS << '\n'; - } else if (IfStmt *ElseIf = dyn_cast(Else)) { - OS << ' '; - PrintRawIfStmt(ElseIf); - } else { - OS << '\n'; - PrintStmt(If->getElse()); - } - } -} - -void StmtPrinter::VisitIfStmt(IfStmt *If) { - Indent(); - PrintRawIfStmt(If); -} - -void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { - Indent() << "switch ("; - PrintExpr(Node->getCond()); - OS << ")"; - - // Pretty print compoundstmt bodies (very common). - if (CompoundStmt *CS = dyn_cast(Node->getBody())) { - OS << " "; - PrintRawCompoundStmt(CS); - OS << "\n"; - } else { - OS << "\n"; - PrintStmt(Node->getBody()); - } -} - -void StmtPrinter::VisitSwitchCase(SwitchCase*) { - assert(0 && "SwitchCase is an abstract class"); -} - -void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { - Indent() << "while ("; - PrintExpr(Node->getCond()); - OS << ")\n"; - PrintStmt(Node->getBody()); -} - -void StmtPrinter::VisitDoStmt(DoStmt *Node) { - Indent() << "do "; - if (CompoundStmt *CS = dyn_cast(Node->getBody())) { - PrintRawCompoundStmt(CS); - OS << " "; - } else { - OS << "\n"; - PrintStmt(Node->getBody()); - Indent(); - } - - OS << "while "; - PrintExpr(Node->getCond()); - OS << ";\n"; -} - -void StmtPrinter::VisitForStmt(ForStmt *Node) { - Indent() << "for ("; - if (Node->getInit()) { - if (DeclStmt *DS = dyn_cast(Node->getInit())) - PrintRawDecl(DS->getDecl()); - else - PrintExpr(cast(Node->getInit())); - } - OS << ";"; - if (Node->getCond()) { - OS << " "; - PrintExpr(Node->getCond()); - } - OS << ";"; - if (Node->getInc()) { - OS << " "; - PrintExpr(Node->getInc()); - } - OS << ") "; - - if (CompoundStmt *CS = dyn_cast(Node->getBody())) { - PrintRawCompoundStmt(CS); - OS << "\n"; - } else { - OS << "\n"; - PrintStmt(Node->getBody()); - } -} - -void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { - Indent() << "for ("; - if (DeclStmt *DS = dyn_cast(Node->getElement())) - PrintRawDecl(DS->getDecl()); - else - PrintExpr(cast(Node->getElement())); - OS << " in "; - PrintExpr(Node->getCollection()); - OS << ") "; - - if (CompoundStmt *CS = dyn_cast(Node->getBody())) { - PrintRawCompoundStmt(CS); - OS << "\n"; - } else { - OS << "\n"; - PrintStmt(Node->getBody()); - } -} - -void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { - Indent() << "goto " << Node->getLabel()->getName() << ";\n"; -} - -void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) { - Indent() << "goto *"; - PrintExpr(Node->getTarget()); - OS << ";\n"; -} - -void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) { - Indent() << "continue;\n"; -} - -void StmtPrinter::VisitBreakStmt(BreakStmt *Node) { - Indent() << "break;\n"; -} - - -void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { - Indent() << "return"; - if (Node->getRetValue()) { - OS << " "; - PrintExpr(Node->getRetValue()); - } - OS << ";\n"; -} - - -void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { - Indent() << "asm "; - - if (Node->isVolatile()) - OS << "volatile "; - - OS << "("; - VisitStringLiteral(Node->getAsmString()); - - // Outputs - if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || - Node->getNumClobbers() != 0) - OS << " : "; - - for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { - if (i != 0) - OS << ", "; - - if (!Node->getOutputName(i).empty()) { - OS << '['; - OS << Node->getOutputName(i); - OS << "] "; - } - - VisitStringLiteral(Node->getOutputConstraint(i)); - OS << " "; - Visit(Node->getOutputExpr(i)); - } - - // Inputs - if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) - OS << " : "; - - for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { - if (i != 0) - OS << ", "; - - if (!Node->getInputName(i).empty()) { - OS << '['; - OS << Node->getInputName(i); - OS << "] "; - } - - VisitStringLiteral(Node->getInputConstraint(i)); - OS << " "; - Visit(Node->getInputExpr(i)); - } - - // Clobbers - if (Node->getNumClobbers() != 0) - OS << " : "; - - for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { - if (i != 0) - OS << ", "; - - VisitStringLiteral(Node->getClobber(i)); - } - - OS << ");\n"; -} - -void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { - Indent() << "@try"; - if (CompoundStmt *TS = dyn_cast(Node->getTryBody())) { - PrintRawCompoundStmt(TS); - OS << "\n"; - } - - for (ObjCAtCatchStmt *catchStmt = - static_cast(Node->getCatchStmts()); - catchStmt; - catchStmt = - static_cast(catchStmt->getNextCatchStmt())) { - Indent() << "@catch("; - if (catchStmt->getCatchParamStmt()) { - if (DeclStmt *DS = dyn_cast(catchStmt->getCatchParamStmt())) - PrintRawDecl(DS->getDecl()); - } - OS << ")"; - if (CompoundStmt *CS = dyn_cast(catchStmt->getCatchBody())) - { - PrintRawCompoundStmt(CS); - OS << "\n"; - } - } - - if (ObjCAtFinallyStmt *FS =static_cast( - Node->getFinallyStmt())) { - Indent() << "@finally"; - PrintRawCompoundStmt(dyn_cast(FS->getFinallyBody())); - OS << "\n"; - } -} - -void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) { -} - -void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) { - Indent() << "@catch (...) { /* todo */ } \n"; -} - -void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) { - Indent() << "@throw"; - if (Node->getThrowExpr()) { - OS << " "; - PrintExpr(Node->getThrowExpr()); - } - OS << ";\n"; -} - -void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) { - Indent() << "@synchronized ("; - PrintExpr(Node->getSynchExpr()); - OS << ")"; - PrintRawCompoundStmt(Node->getSynchBody()); - OS << "\n"; -} - -//===----------------------------------------------------------------------===// -// Expr printing methods. -//===----------------------------------------------------------------------===// - -void StmtPrinter::VisitExpr(Expr *Node) { - OS << "<>"; -} - -void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { - OS << Node->getDecl()->getName(); -} - -void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { - if (Node->getBase()) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); - } - OS << Node->getDecl()->getName(); -} - -void StmtPrinter::VisitPreDefinedExpr(PreDefinedExpr *Node) { - switch (Node->getIdentType()) { - default: - assert(0 && "unknown case"); - case PreDefinedExpr::Func: - OS << "__func__"; - break; - case PreDefinedExpr::Function: - OS << "__FUNCTION__"; - break; - case PreDefinedExpr::PrettyFunction: - OS << "__PRETTY_FUNCTION__"; - break; - } -} - -void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { - // FIXME should print an L for wchar_t constants - unsigned value = Node->getValue(); - switch (value) { - case '\\': - OS << "'\\\\'"; - break; - case '\'': - OS << "'\\''"; - break; - case '\a': - // TODO: K&R: the meaning of '\\a' is different in traditional C - OS << "'\\a'"; - break; - case '\b': - OS << "'\\b'"; - break; - // Nonstandard escape sequence. - /*case '\e': - OS << "'\\e'"; - break;*/ - case '\f': - OS << "'\\f'"; - break; - case '\n': - OS << "'\\n'"; - break; - case '\r': - OS << "'\\r'"; - break; - case '\t': - OS << "'\\t'"; - break; - case '\v': - OS << "'\\v'"; - break; - default: - if (value < 256 && isprint(value)) { - OS << "'" << (char)value << "'"; - } else if (value < 256) { - OS << "'\\x" << std::hex << value << std::dec << "'"; - } else { - // FIXME what to really do here? - OS << value; - } - } -} - -void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { - bool isSigned = Node->getType()->isSignedIntegerType(); - OS << Node->getValue().toString(10, isSigned); - - // Emit suffixes. Integer literals are always a builtin integer type. - switch (cast(Node->getType().getCanonicalType())->getKind()) { - default: assert(0 && "Unexpected type for integer literal!"); - case BuiltinType::Int: break; // no suffix. - case BuiltinType::UInt: OS << 'U'; break; - case BuiltinType::Long: OS << 'L'; break; - case BuiltinType::ULong: OS << "UL"; break; - case BuiltinType::LongLong: OS << "LL"; break; - case BuiltinType::ULongLong: OS << "ULL"; break; - } -} -void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { - // FIXME: print value more precisely. - OS << Node->getValueAsDouble(); -} - -void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { - PrintExpr(Node->getSubExpr()); - OS << "i"; -} - -void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { - if (Str->isWide()) OS << 'L'; - OS << '"'; - - // FIXME: this doesn't print wstrings right. - for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { - switch (Str->getStrData()[i]) { - default: OS << Str->getStrData()[i]; break; - // Handle some common ones to make dumps prettier. - case '\\': OS << "\\\\"; break; - case '"': OS << "\\\""; break; - case '\n': OS << "\\n"; break; - case '\t': OS << "\\t"; break; - case '\a': OS << "\\a"; break; - case '\b': OS << "\\b"; break; - } - } - OS << '"'; -} -void StmtPrinter::VisitParenExpr(ParenExpr *Node) { - OS << "("; - PrintExpr(Node->getSubExpr()); - OS << ")"; -} -void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { - if (!Node->isPostfix()) { - OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); - - // Print a space if this is an "identifier operator" like sizeof or __real. - switch (Node->getOpcode()) { - default: break; - case UnaryOperator::SizeOf: - case UnaryOperator::AlignOf: - case UnaryOperator::Real: - case UnaryOperator::Imag: - case UnaryOperator::Extension: - OS << ' '; - break; - } - } - PrintExpr(Node->getSubExpr()); - - if (Node->isPostfix()) - OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); -} - -bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { - if (isa(E)) { - // Base case, print the type and comma. - OS << E->getType().getAsString() << ", "; - return true; - } else if (ArraySubscriptExpr *ASE = dyn_cast(E)) { - PrintOffsetOfDesignator(ASE->getLHS()); - OS << "["; - PrintExpr(ASE->getRHS()); - OS << "]"; - return false; - } else { - MemberExpr *ME = cast(E); - bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); - OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getName(); - return false; - } -} - -void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { - OS << "__builtin_offsetof("; - PrintOffsetOfDesignator(Node->getSubExpr()); - OS << ")"; -} - -void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { - OS << (Node->isSizeOf() ? "sizeof(" : "__alignof("); - OS << Node->getArgumentType().getAsString() << ")"; -} -void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { - PrintExpr(Node->getLHS()); - OS << "["; - PrintExpr(Node->getRHS()); - OS << "]"; -} - -void StmtPrinter::VisitCallExpr(CallExpr *Call) { - PrintExpr(Call->getCallee()); - OS << "("; - for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { - if (i) OS << ", "; - PrintExpr(Call->getArg(i)); - } - OS << ")"; -} -void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); - - FieldDecl *Field = Node->getMemberDecl(); - assert(Field && "MemberExpr should alway reference a field!"); - OS << Field->getName(); -} -void StmtPrinter::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { - PrintExpr(Node->getBase()); - OS << "."; - OS << Node->getAccessor().getName(); -} -void StmtPrinter::VisitCastExpr(CastExpr *Node) { - OS << "(" << Node->getType().getAsString() << ")"; - PrintExpr(Node->getSubExpr()); -} -void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { - OS << "(" << Node->getType().getAsString() << ")"; - PrintExpr(Node->getInitializer()); -} -void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) { - // No need to print anything, simply forward to the sub expression. - PrintExpr(Node->getSubExpr()); -} -void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { - PrintExpr(Node->getLHS()); - OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; - PrintExpr(Node->getRHS()); -} -void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { - PrintExpr(Node->getLHS()); - OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; - PrintExpr(Node->getRHS()); -} -void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { - PrintExpr(Node->getCond()); - - if (Node->getLHS()) { - OS << " ? "; - PrintExpr(Node->getLHS()); - OS << " : "; - } - else { // Handle GCC extention where LHS can be NULL. - OS << " ?: "; - } - - PrintExpr(Node->getRHS()); -} - -// GNU extensions. - -void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { - OS << "&&" << Node->getLabel()->getName(); -} - -void StmtPrinter::VisitStmtExpr(StmtExpr *E) { - OS << "("; - PrintRawCompoundStmt(E->getSubStmt()); - OS << ")"; -} - -void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { - OS << "__builtin_types_compatible_p("; - OS << Node->getArgType1().getAsString() << ","; - OS << Node->getArgType2().getAsString() << ")"; -} - -void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { - OS << "__builtin_choose_expr("; - PrintExpr(Node->getCond()); - OS << ", "; - PrintExpr(Node->getLHS()); - OS << ", "; - PrintExpr(Node->getRHS()); - OS << ")"; -} - -void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) { - OS << "__builtin_overload("; - for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { - if (i) OS << ", "; - PrintExpr(Node->getExpr(i)); - } - OS << ")"; -} - -void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { - OS << "{ "; - for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { - if (i) OS << ", "; - PrintExpr(Node->getInit(i)); - } - OS << " }"; -} - -void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { - OS << "va_arg("; - PrintExpr(Node->getSubExpr()); - OS << ", "; - OS << Node->getType().getAsString(); - OS << ")"; -} - -// C++ - -void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) { - OS << CXXCastExpr::getOpcodeStr(Node->getOpcode()) << '<'; - OS << Node->getDestType().getAsString() << ">("; - PrintExpr(Node->getSubExpr()); - OS << ")"; -} - -void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { - OS << (Node->getValue() ? "true" : "false"); -} - -void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { - if (Node->getSubExpr() == 0) - OS << "throw"; - else { - OS << "throw "; - PrintExpr(Node->getSubExpr()); - } -} - -// Obj-C - -void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { - OS << "@"; - VisitStringLiteral(Node->getString()); -} - -void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { - OS << "@encode(" << Node->getEncodedType().getAsString() << ")"; -} - -void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { - OS << "@selector(" << Node->getSelector().getName() << ")"; -} - -void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - OS << "@protocol(" << Node->getProtocol()->getName() << ")"; -} - -void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { - OS << "["; - Expr *receiver = Mess->getReceiver(); - if (receiver) PrintExpr(receiver); - else OS << Mess->getClassName()->getName(); - Selector &selector = Mess->getSelector(); - if (selector.isUnarySelector()) { - OS << " " << selector.getIdentifierInfoForSlot(0)->getName(); - } else { - for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { - if (selector.getIdentifierInfoForSlot(i)) - OS << selector.getIdentifierInfoForSlot(i)->getName() << ":"; - else - OS << ":"; - PrintExpr(Mess->getArg(i)); - } - } - OS << "]"; -} - -//===----------------------------------------------------------------------===// -// Stmt method implementations -//===----------------------------------------------------------------------===// - -void Stmt::dumpPretty() const { - printPretty(*llvm::cerr.stream()); -} - -void Stmt::printPretty(std::ostream &OS, PrinterHelper* Helper) const { - if (this == 0) { - OS << ""; - return; - } - - StmtPrinter P(OS, Helper); - P.Visit(const_cast(this)); -} - -//===----------------------------------------------------------------------===// -// PrinterHelper -//===----------------------------------------------------------------------===// - -// Implement virtual destructor. -PrinterHelper::~PrinterHelper() {} diff --git a/clang/AST/StmtSerialization.cpp b/clang/AST/StmtSerialization.cpp deleted file mode 100644 index 433e8e27026..00000000000 --- a/clang/AST/StmtSerialization.cpp +++ /dev/null @@ -1,1001 +0,0 @@ -//===--- StmtSerialization.cpp - Serialization of Statements --------------===// -// -// 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 type-specific methods for serializing statements -// and expressions. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Expr.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using namespace clang; -using llvm::Serializer; -using llvm::Deserializer; - -void Stmt::Emit(Serializer& S) const { - S.FlushRecord(); - S.EmitInt(getStmtClass()); - EmitImpl(S); - S.FlushRecord(); -} - -Stmt* Stmt::Create(Deserializer& D) { - StmtClass SC = static_cast(D.ReadInt()); - - switch (SC) { - default: - assert (false && "Not implemented."); - return NULL; - - case AddrLabelExprClass: - return AddrLabelExpr::CreateImpl(D); - - case ArraySubscriptExprClass: - return ArraySubscriptExpr::CreateImpl(D); - - case AsmStmtClass: - return AsmStmt::CreateImpl(D); - - case BinaryOperatorClass: - return BinaryOperator::CreateImpl(D); - - case BreakStmtClass: - return BreakStmt::CreateImpl(D); - - case CallExprClass: - return CallExpr::CreateImpl(D); - - case CaseStmtClass: - return CaseStmt::CreateImpl(D); - - case CastExprClass: - return CastExpr::CreateImpl(D); - - case CharacterLiteralClass: - return CharacterLiteral::CreateImpl(D); - - case CompoundAssignOperatorClass: - return CompoundAssignOperator::CreateImpl(D); - - case CompoundLiteralExprClass: - return CompoundLiteralExpr::CreateImpl(D); - - case CompoundStmtClass: - return CompoundStmt::CreateImpl(D); - - case ConditionalOperatorClass: - return ConditionalOperator::CreateImpl(D); - - case ContinueStmtClass: - return ContinueStmt::CreateImpl(D); - - case DeclRefExprClass: - return DeclRefExpr::CreateImpl(D); - - case DeclStmtClass: - return DeclStmt::CreateImpl(D); - - case DefaultStmtClass: - return DefaultStmt::CreateImpl(D); - - case DoStmtClass: - return DoStmt::CreateImpl(D); - - case FloatingLiteralClass: - return FloatingLiteral::CreateImpl(D); - - case ForStmtClass: - return ForStmt::CreateImpl(D); - - case GotoStmtClass: - return GotoStmt::CreateImpl(D); - - case IfStmtClass: - return IfStmt::CreateImpl(D); - - case ImaginaryLiteralClass: - return ImaginaryLiteral::CreateImpl(D); - - case ImplicitCastExprClass: - return ImplicitCastExpr::CreateImpl(D); - - case IndirectGotoStmtClass: - return IndirectGotoStmt::CreateImpl(D); - - case InitListExprClass: - return InitListExpr::CreateImpl(D); - - case IntegerLiteralClass: - return IntegerLiteral::CreateImpl(D); - - case LabelStmtClass: - return LabelStmt::CreateImpl(D); - - case MemberExprClass: - return MemberExpr::CreateImpl(D); - - case NullStmtClass: - return NullStmt::CreateImpl(D); - - case ParenExprClass: - return ParenExpr::CreateImpl(D); - - case PreDefinedExprClass: - return PreDefinedExpr::CreateImpl(D); - - case ReturnStmtClass: - return ReturnStmt::CreateImpl(D); - - case SizeOfAlignOfTypeExprClass: - return SizeOfAlignOfTypeExpr::CreateImpl(D); - - case StmtExprClass: - return StmtExpr::CreateImpl(D); - - case StringLiteralClass: - return StringLiteral::CreateImpl(D); - - case SwitchStmtClass: - return SwitchStmt::CreateImpl(D); - - case UnaryOperatorClass: - return UnaryOperator::CreateImpl(D); - - case WhileStmtClass: - return WhileStmt::CreateImpl(D); - - //==--------------------------------------==// - // Objective C - //==--------------------------------------==// - - case ObjCAtCatchStmtClass: - return ObjCAtCatchStmt::CreateImpl(D); - - case ObjCAtFinallyStmtClass: - return ObjCAtFinallyStmt::CreateImpl(D); - - case ObjCAtSynchronizedStmtClass: - return ObjCAtSynchronizedStmt::CreateImpl(D); - - case ObjCAtThrowStmtClass: - return ObjCAtThrowStmt::CreateImpl(D); - - case ObjCAtTryStmtClass: - return ObjCAtTryStmt::CreateImpl(D); - - case ObjCEncodeExprClass: - return ObjCEncodeExpr::CreateImpl(D); - - case ObjCForCollectionStmtClass: - return ObjCForCollectionStmt::CreateImpl(D); - - case ObjCIvarRefExprClass: - return ObjCIvarRefExpr::CreateImpl(D); - - case ObjCSelectorExprClass: - return ObjCSelectorExpr::CreateImpl(D); - - case ObjCStringLiteralClass: - return ObjCStringLiteral::CreateImpl(D); - } -} - -//===----------------------------------------------------------------------===// -// C Serialization -//===----------------------------------------------------------------------===// - -void AddrLabelExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(AmpAmpLoc); - S.Emit(LabelLoc); - S.EmitPtr(Label); -} - -AddrLabelExpr* AddrLabelExpr::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation AALoc = SourceLocation::ReadVal(D); - SourceLocation LLoc = SourceLocation::ReadVal(D); - AddrLabelExpr* expr = new AddrLabelExpr(AALoc,LLoc,NULL,t); - D.ReadPtr(expr->Label); // Pointer may be backpatched. - return expr; -} - -void ArraySubscriptExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(RBracketLoc); - S.BatchEmitOwnedPtrs(getLHS(),getRHS()); -} - -ArraySubscriptExpr* ArraySubscriptExpr::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation L = SourceLocation::ReadVal(D); - Expr *LHS, *RHS; - D.BatchReadOwnedPtrs(LHS,RHS); - return new ArraySubscriptExpr(LHS,RHS,t,L); -} - -void AsmStmt::EmitImpl(Serializer& S) const { - S.Emit(AsmLoc); - - getAsmString()->EmitImpl(S); - S.Emit(RParenLoc); - - S.EmitBool(IsVolatile); - S.EmitBool(IsSimple); - S.EmitInt(NumOutputs); - S.EmitInt(NumInputs); - - unsigned size = NumOutputs + NumInputs; - - for (unsigned i = 0; i < size; ++i) - S.EmitCStr(Names[i].c_str()); - - for (unsigned i = 0; i < size; ++i) - Constraints[i]->EmitImpl(S); - - for (unsigned i = 0; i < size; ++i) - S.EmitOwnedPtr(Exprs[i]); - - S.EmitInt(Clobbers.size()); - for (unsigned i = 0, e = Clobbers.size(); i != e; ++i) - Clobbers[i]->EmitImpl(S); -} - -AsmStmt* AsmStmt::CreateImpl(Deserializer& D) { - SourceLocation ALoc = SourceLocation::ReadVal(D); - StringLiteral *AsmStr = StringLiteral::CreateImpl(D); - SourceLocation PLoc = SourceLocation::ReadVal(D); - - bool IsVolatile = D.ReadBool(); - bool IsSimple = D.ReadBool(); - AsmStmt *Stmt = new AsmStmt(ALoc, IsSimple, IsVolatile, 0, 0, 0, 0, 0, - AsmStr, - 0, 0, PLoc); - - Stmt->NumOutputs = D.ReadInt(); - Stmt->NumInputs = D.ReadInt(); - - unsigned size = Stmt->NumOutputs + Stmt->NumInputs; - - Stmt->Names.reserve(size); - for (unsigned i = 0; i < size; ++i) { - std::vector data; - D.ReadCStr(data, false); - - Stmt->Names.push_back(std::string(data.begin(), data.end())); - } - - Stmt->Constraints.reserve(size); - for (unsigned i = 0; i < size; ++i) - Stmt->Constraints.push_back(StringLiteral::CreateImpl(D)); - - Stmt->Exprs.reserve(size); - for (unsigned i = 0; i < size; ++i) - Stmt->Exprs.push_back(D.ReadOwnedPtr()); - - unsigned NumClobbers = D.ReadInt(); - Stmt->Clobbers.reserve(NumClobbers); - for (unsigned i = 0; i < NumClobbers; ++i) - Stmt->Clobbers.push_back(StringLiteral::CreateImpl(D)); - - return Stmt; -} - -void BinaryOperator::EmitImpl(Serializer& S) const { - S.EmitInt(Opc); - S.Emit(OpLoc);; - S.Emit(getType()); - S.BatchEmitOwnedPtrs(getLHS(),getRHS()); -} - -BinaryOperator* BinaryOperator::CreateImpl(Deserializer& D) { - Opcode Opc = static_cast(D.ReadInt()); - SourceLocation OpLoc = SourceLocation::ReadVal(D); - QualType Result = QualType::ReadVal(D); - Expr *LHS, *RHS; - D.BatchReadOwnedPtrs(LHS,RHS); - - return new BinaryOperator(LHS,RHS,Opc,Result,OpLoc); -} - -void BreakStmt::EmitImpl(Serializer& S) const { - S.Emit(BreakLoc); -} - -BreakStmt* BreakStmt::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - return new BreakStmt(Loc); -} - -void CallExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(RParenLoc); - S.EmitInt(NumArgs); - S.BatchEmitOwnedPtrs(NumArgs+1,SubExprs); -} - -CallExpr* CallExpr::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation L = SourceLocation::ReadVal(D); - unsigned NumArgs = D.ReadInt(); - Expr** SubExprs = new Expr*[NumArgs+1]; - D.BatchReadOwnedPtrs(NumArgs+1,SubExprs); - - return new CallExpr(SubExprs,NumArgs,t,L); -} - -void CaseStmt::EmitImpl(Serializer& S) const { - S.Emit(CaseLoc); - S.EmitPtr(getNextSwitchCase()); - S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubExprs[0]); -} - -CaseStmt* CaseStmt::CreateImpl(Deserializer& D) { - SourceLocation CaseLoc = SourceLocation::ReadVal(D); - CaseStmt* stmt = new CaseStmt(NULL,NULL,NULL,CaseLoc); - D.ReadPtr(stmt->NextSwitchCase); - D.BatchReadOwnedPtrs((unsigned) END_EXPR,&stmt->SubExprs[0]); - return stmt; -} - -void CastExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(Loc); - S.EmitOwnedPtr(Op); -} - -CastExpr* CastExpr::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation Loc = SourceLocation::ReadVal(D); - Expr* Op = D.ReadOwnedPtr(); - return new CastExpr(t,Op,Loc); -} - - -void CharacterLiteral::EmitImpl(Serializer& S) const { - S.Emit(Value); - S.Emit(Loc); - S.Emit(getType()); -} - -CharacterLiteral* CharacterLiteral::CreateImpl(Deserializer& D) { - unsigned value = D.ReadInt(); - SourceLocation Loc = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - return new CharacterLiteral(value,T,Loc); -} - -void CompoundAssignOperator::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(ComputationType); - S.Emit(getOperatorLoc()); - S.EmitInt(getOpcode()); - S.BatchEmitOwnedPtrs(getLHS(),getRHS()); -} - -CompoundAssignOperator* -CompoundAssignOperator::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - QualType c = QualType::ReadVal(D); - SourceLocation L = SourceLocation::ReadVal(D); - Opcode Opc = static_cast(D.ReadInt()); - Expr* LHS, *RHS; - D.BatchReadOwnedPtrs(LHS,RHS); - - return new CompoundAssignOperator(LHS,RHS,Opc,t,c,L); -} - -void CompoundLiteralExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(getLParenLoc()); - S.EmitBool(isFileScope()); - S.EmitOwnedPtr(Init); -} - -CompoundLiteralExpr* CompoundLiteralExpr::CreateImpl(Deserializer& D) { - QualType Q = QualType::ReadVal(D); - SourceLocation L = SourceLocation::ReadVal(D); - bool fileScope = D.ReadBool(); - Expr* Init = D.ReadOwnedPtr(); - return new CompoundLiteralExpr(L, Q, Init, fileScope); -} - -void CompoundStmt::EmitImpl(Serializer& S) const { - S.Emit(LBracLoc); - S.Emit(RBracLoc); - S.Emit(Body.size()); - - for (const_body_iterator I=body_begin(), E=body_end(); I!=E; ++I) - S.EmitOwnedPtr(*I); -} - -CompoundStmt* CompoundStmt::CreateImpl(Deserializer& D) { - SourceLocation LB = SourceLocation::ReadVal(D); - SourceLocation RB = SourceLocation::ReadVal(D); - unsigned size = D.ReadInt(); - - CompoundStmt* stmt = new CompoundStmt(NULL,0,LB,RB); - - stmt->Body.reserve(size); - - for (unsigned i = 0; i < size; ++i) - stmt->Body.push_back(D.ReadOwnedPtr()); - - return stmt; -} - -void ConditionalOperator::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.BatchEmitOwnedPtrs((unsigned) END_EXPR, SubExprs); -} - -ConditionalOperator* ConditionalOperator::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - ConditionalOperator* c = new ConditionalOperator(NULL,NULL,NULL,t); - D.BatchReadOwnedPtrs((unsigned) END_EXPR, c->SubExprs); - return c; -} - -void ContinueStmt::EmitImpl(Serializer& S) const { - S.Emit(ContinueLoc); -} - -ContinueStmt* ContinueStmt::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - return new ContinueStmt(Loc); -} - -void DeclStmt::EmitImpl(Serializer& S) const { - // FIXME: special handling for struct decls. - S.EmitOwnedPtr(getDecl()); - S.Emit(StartLoc); - S.Emit(EndLoc); -} - -void DeclRefExpr::EmitImpl(Serializer& S) const { - S.Emit(Loc); - S.Emit(getType()); - - // Some DeclRefExprs can actually hold the owning reference to a FunctionDecl. - // This occurs when an implicitly defined function is called, and - // the decl does not appear in the source file. We thus check if the - // decl pointer has been registered, and if not, emit an owned pointer. - - // FIXME: While this will work for serialization, it won't work for - // memory management. The only reason this works for serialization is - // because we are tracking all serialized pointers. Either DeclRefExpr - // needs an explicit bit indicating that it owns the the object, - // or we need a different ownership model. - - const Decl* d = getDecl(); - - if (!S.isRegistered(d)) { - assert (isa(d) - && "DeclRefExpr can only own FunctionDecls for implicitly def. funcs."); - - S.EmitBool(true); - S.EmitOwnedPtr(d); - } - else { - S.EmitBool(false); - S.EmitPtr(d); - } -} - -DeclRefExpr* DeclRefExpr::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - bool OwnsDecl = D.ReadBool(); - ValueDecl* decl; - - if (!OwnsDecl) - D.ReadPtr(decl,false); // No backpatching. - else - decl = cast(D.ReadOwnedPtr()); - - return new DeclRefExpr(decl,T,Loc); -} - - -DeclStmt* DeclStmt::CreateImpl(Deserializer& D) { - ScopedDecl* decl = cast(D.ReadOwnedPtr()); - SourceLocation StartLoc = SourceLocation::ReadVal(D); - SourceLocation EndLoc = SourceLocation::ReadVal(D); - return new DeclStmt(decl, StartLoc, EndLoc); -} - -void DefaultStmt::EmitImpl(Serializer& S) const { - S.Emit(DefaultLoc); - S.EmitOwnedPtr(getSubStmt()); - S.EmitPtr(getNextSwitchCase()); -} - -DefaultStmt* DefaultStmt::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - Stmt* SubStmt = D.ReadOwnedPtr(); - - DefaultStmt* stmt = new DefaultStmt(Loc,SubStmt); - stmt->setNextSwitchCase(D.ReadPtr()); - - return stmt; -} - -void DoStmt::EmitImpl(Serializer& S) const { - S.Emit(DoLoc); - S.EmitOwnedPtr(getCond()); - S.EmitOwnedPtr(getBody()); -} - -DoStmt* DoStmt::CreateImpl(Deserializer& D) { - SourceLocation DoLoc = SourceLocation::ReadVal(D); - Expr* Cond = D.ReadOwnedPtr(); - Stmt* Body = D.ReadOwnedPtr(); - return new DoStmt(Body,Cond,DoLoc); -} - -void FloatingLiteral::EmitImpl(Serializer& S) const { - S.Emit(Loc); - S.Emit(getType()); - S.EmitBool(isExact()); - S.Emit(Value); -} - -FloatingLiteral* FloatingLiteral::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - QualType t = QualType::ReadVal(D); - bool isExact = D.ReadBool(); - llvm::APFloat Val = llvm::APFloat::ReadVal(D); - FloatingLiteral* expr = new FloatingLiteral(Val,&isExact,t,Loc); - return expr; -} - -void ForStmt::EmitImpl(Serializer& S) const { - S.Emit(ForLoc); - S.EmitOwnedPtr(getInit()); - S.EmitOwnedPtr(getCond()); - S.EmitOwnedPtr(getInc()); - S.EmitOwnedPtr(getBody()); -} - -ForStmt* ForStmt::CreateImpl(Deserializer& D) { - SourceLocation ForLoc = SourceLocation::ReadVal(D); - Stmt* Init = D.ReadOwnedPtr(); - Expr* Cond = D.ReadOwnedPtr(); - Expr* Inc = D.ReadOwnedPtr(); - Stmt* Body = D.ReadOwnedPtr(); - return new ForStmt(Init,Cond,Inc,Body,ForLoc); -} - -void GotoStmt::EmitImpl(Serializer& S) const { - S.Emit(GotoLoc); - S.Emit(LabelLoc); - S.EmitPtr(Label); -} - -GotoStmt* GotoStmt::CreateImpl(Deserializer& D) { - SourceLocation GotoLoc = SourceLocation::ReadVal(D); - SourceLocation LabelLoc = SourceLocation::ReadVal(D); - GotoStmt* stmt = new GotoStmt(NULL,GotoLoc,LabelLoc); - D.ReadPtr(stmt->Label); // This pointer may be backpatched later. - return stmt; -} - -void IfStmt::EmitImpl(Serializer& S) const { - S.Emit(IfLoc); - S.EmitOwnedPtr(getCond()); - S.EmitOwnedPtr(getThen()); - S.EmitOwnedPtr(getElse()); -} - -IfStmt* IfStmt::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - Expr* Cond = D.ReadOwnedPtr(); - Stmt* Then = D.ReadOwnedPtr(); - Stmt* Else = D.ReadOwnedPtr(); - return new IfStmt(L,Cond,Then,Else); -} - -void ImaginaryLiteral::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.EmitOwnedPtr(Val); -} - -ImaginaryLiteral* ImaginaryLiteral::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - Expr* expr = D.ReadOwnedPtr(); - assert (isa(expr) || isa(expr)); - return new ImaginaryLiteral(expr,t); -} - -void ImplicitCastExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.EmitOwnedPtr(Op); -} - -ImplicitCastExpr* ImplicitCastExpr::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - Expr* Op = D.ReadOwnedPtr(); - return new ImplicitCastExpr(t,Op); -} - -void IndirectGotoStmt::EmitImpl(Serializer& S) const { - S.EmitOwnedPtr(Target); -} - -IndirectGotoStmt* IndirectGotoStmt::CreateImpl(Deserializer& D) { - Expr* Target = D.ReadOwnedPtr(); - return new IndirectGotoStmt(Target); -} - -void InitListExpr::EmitImpl(Serializer& S) const { - S.Emit(LBraceLoc); - S.Emit(RBraceLoc); - S.EmitInt(NumInits); - S.BatchEmitOwnedPtrs(NumInits,InitExprs); -} - -InitListExpr* InitListExpr::CreateImpl(Deserializer& D) { - InitListExpr* expr = new InitListExpr(); - expr->LBraceLoc = SourceLocation::ReadVal(D); - expr->RBraceLoc = SourceLocation::ReadVal(D); - expr->NumInits = D.ReadInt(); - assert(expr->NumInits); - expr->InitExprs = new Expr*[expr->NumInits]; - D.BatchReadOwnedPtrs(expr->NumInits,expr->InitExprs); - return expr; -} - -void IntegerLiteral::EmitImpl(Serializer& S) const { - S.Emit(Loc); - S.Emit(getType()); - S.Emit(getValue()); -} - -IntegerLiteral* IntegerLiteral::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - - // Create a dummy APInt because it is more efficient to deserialize - // it in place with the deserialized IntegerLiteral. (fewer copies) - llvm::APInt temp; - IntegerLiteral* expr = new IntegerLiteral(temp,T,Loc); - D.Read(expr->Value); - - return expr; -} - -void LabelStmt::EmitImpl(Serializer& S) const { - S.EmitPtr(Label); - S.Emit(IdentLoc); - S.EmitOwnedPtr(SubStmt); -} - -LabelStmt* LabelStmt::CreateImpl(Deserializer& D) { - IdentifierInfo* Label = D.ReadPtr(); - SourceLocation IdentLoc = SourceLocation::ReadVal(D); - Stmt* SubStmt = D.ReadOwnedPtr(); - return new LabelStmt(IdentLoc,Label,SubStmt); -} - -void MemberExpr::EmitImpl(Serializer& S) const { - S.Emit(MemberLoc); - S.EmitPtr(MemberDecl); - S.EmitBool(IsArrow); - S.Emit(getType()); - S.EmitOwnedPtr(Base); -} - -MemberExpr* MemberExpr::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - FieldDecl* MemberDecl = cast(D.ReadPtr()); - bool IsArrow = D.ReadBool(); - QualType T = QualType::ReadVal(D); - Expr* base = D.ReadOwnedPtr(); - - return new MemberExpr(base,IsArrow,MemberDecl,L,T); -} - -void NullStmt::EmitImpl(Serializer& S) const { - S.Emit(SemiLoc); -} - -NullStmt* NullStmt::CreateImpl(Deserializer& D) { - SourceLocation SemiLoc = SourceLocation::ReadVal(D); - return new NullStmt(SemiLoc); -} - -void ParenExpr::EmitImpl(Serializer& S) const { - S.Emit(L); - S.Emit(R); - S.EmitOwnedPtr(Val); -} - -ParenExpr* ParenExpr::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - SourceLocation R = SourceLocation::ReadVal(D); - Expr* val = D.ReadOwnedPtr(); - return new ParenExpr(L,R,val); -} - -void PreDefinedExpr::EmitImpl(Serializer& S) const { - S.Emit(Loc); - S.EmitInt(getIdentType()); - S.Emit(getType()); -} - -PreDefinedExpr* PreDefinedExpr::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - IdentType it = static_cast(D.ReadInt()); - QualType Q = QualType::ReadVal(D); - return new PreDefinedExpr(Loc,Q,it); -} - -void ReturnStmt::EmitImpl(Serializer& S) const { - S.Emit(RetLoc); - S.EmitOwnedPtr(RetExpr); -} - -ReturnStmt* ReturnStmt::CreateImpl(Deserializer& D) { - SourceLocation RetLoc = SourceLocation::ReadVal(D); - Expr* RetExpr = D.ReadOwnedPtr(); - return new ReturnStmt(RetLoc,RetExpr); -} - -void SizeOfAlignOfTypeExpr::EmitImpl(Serializer& S) const { - S.EmitBool(isSizeof); - S.Emit(Ty); - S.Emit(getType()); - S.Emit(OpLoc); - S.Emit(RParenLoc); -} - -SizeOfAlignOfTypeExpr* SizeOfAlignOfTypeExpr::CreateImpl(Deserializer& D) { - bool isSizeof = D.ReadBool(); - QualType Ty = QualType::ReadVal(D); - QualType Res = QualType::ReadVal(D); - SourceLocation OpLoc = SourceLocation::ReadVal(D); - SourceLocation RParenLoc = SourceLocation::ReadVal(D); - - return new SizeOfAlignOfTypeExpr(isSizeof,Ty,Res,OpLoc,RParenLoc); -} - -void StmtExpr::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(LParenLoc); - S.Emit(RParenLoc); - S.EmitOwnedPtr(SubStmt); -} - -StmtExpr* StmtExpr::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation L = SourceLocation::ReadVal(D); - SourceLocation R = SourceLocation::ReadVal(D); - CompoundStmt* SubStmt = cast(D.ReadOwnedPtr()); - return new StmtExpr(SubStmt,t,L,R); -} - -void StringLiteral::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(firstTokLoc); - S.Emit(lastTokLoc); - S.EmitBool(isWide()); - S.Emit(getByteLength()); - - for (unsigned i = 0 ; i < ByteLength; ++i) - S.EmitInt(StrData[i]); -} - -StringLiteral* StringLiteral::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation firstTokLoc = SourceLocation::ReadVal(D); - SourceLocation lastTokLoc = SourceLocation::ReadVal(D); - bool isWide = D.ReadBool(); - unsigned ByteLength = D.ReadInt(); - - StringLiteral* sl = new StringLiteral(NULL,0,isWide,t,firstTokLoc,lastTokLoc); - - char* StrData = new char[ByteLength]; - for (unsigned i = 0; i < ByteLength; ++i) - StrData[i] = (char) D.ReadInt(); - - sl->ByteLength = ByteLength; - sl->StrData = StrData; - - return sl; -} - -void SwitchStmt::EmitImpl(Serializer& S) const { - S.Emit(SwitchLoc); - S.EmitOwnedPtr(getCond()); - S.EmitOwnedPtr(getBody()); - S.EmitPtr(FirstCase); -} - -SwitchStmt* SwitchStmt::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - Stmt* Cond = D.ReadOwnedPtr(); - Stmt* Body = D.ReadOwnedPtr(); - SwitchCase* FirstCase = cast(D.ReadPtr()); - - SwitchStmt* stmt = new SwitchStmt(cast(Cond)); - stmt->setBody(Body,Loc); - stmt->FirstCase = FirstCase; - - return stmt; -} - -void UnaryOperator::EmitImpl(Serializer& S) const { - S.Emit(getType()); - S.Emit(Loc); - S.EmitInt(Opc); - S.EmitOwnedPtr(Val); -} - -UnaryOperator* UnaryOperator::CreateImpl(Deserializer& D) { - QualType t = QualType::ReadVal(D); - SourceLocation L = SourceLocation::ReadVal(D); - Opcode Opc = static_cast(D.ReadInt()); - Expr* Val = D.ReadOwnedPtr(); - return new UnaryOperator(Val,Opc,t,L); -} - -void WhileStmt::EmitImpl(Serializer& S) const { - S.Emit(WhileLoc); - S.EmitOwnedPtr(getCond()); - S.EmitOwnedPtr(getBody()); -} - -WhileStmt* WhileStmt::CreateImpl(Deserializer& D) { - SourceLocation WhileLoc = SourceLocation::ReadVal(D); - Expr* Cond = D.ReadOwnedPtr(); - Stmt* Body = D.ReadOwnedPtr(); - return new WhileStmt(Cond,Body,WhileLoc); -} - -//===----------------------------------------------------------------------===// -// Objective C Serialization -//===----------------------------------------------------------------------===// - -void ObjCAtCatchStmt::EmitImpl(Serializer& S) const { - S.Emit(AtCatchLoc); - S.Emit(RParenLoc); - S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubExprs[0]); -} - -ObjCAtCatchStmt* ObjCAtCatchStmt::CreateImpl(Deserializer& D) { - SourceLocation AtCatchLoc = SourceLocation::ReadVal(D); - SourceLocation RParenLoc = SourceLocation::ReadVal(D); - - ObjCAtCatchStmt* stmt = new ObjCAtCatchStmt(AtCatchLoc,RParenLoc); - D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubExprs[0]); - - return stmt; -} - -void ObjCAtFinallyStmt::EmitImpl(Serializer& S) const { - S.Emit(AtFinallyLoc); - S.EmitOwnedPtr(AtFinallyStmt); -} - -ObjCAtFinallyStmt* ObjCAtFinallyStmt::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - Stmt* AtFinallyStmt = D.ReadOwnedPtr(); - return new ObjCAtFinallyStmt(Loc,AtFinallyStmt); -} - -void ObjCAtSynchronizedStmt::EmitImpl(Serializer& S) const { - S.Emit(AtSynchronizedLoc); - S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubStmts[0]); - } - -ObjCAtSynchronizedStmt* ObjCAtSynchronizedStmt::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - ObjCAtSynchronizedStmt* stmt = new ObjCAtSynchronizedStmt(L,0,0); - D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]); - return stmt; -} - -void ObjCAtThrowStmt::EmitImpl(Serializer& S) const { - S.Emit(AtThrowLoc); - S.EmitOwnedPtr(Throw); -} - -ObjCAtThrowStmt* ObjCAtThrowStmt::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - Stmt* Throw = D.ReadOwnedPtr(); - return new ObjCAtThrowStmt(L,Throw); -} - -void ObjCAtTryStmt::EmitImpl(Serializer& S) const { - S.Emit(AtTryLoc); - S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubStmts[0]); -} - -ObjCAtTryStmt* ObjCAtTryStmt::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - ObjCAtTryStmt* stmt = new ObjCAtTryStmt(L,NULL,NULL,NULL); - D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]); - return stmt; -} - -void ObjCEncodeExpr::EmitImpl(Serializer& S) const { - S.Emit(AtLoc); - S.Emit(RParenLoc); - S.Emit(getType()); - S.Emit(EncType); -} - -ObjCEncodeExpr* ObjCEncodeExpr::CreateImpl(Deserializer& D) { - SourceLocation AtLoc = SourceLocation::ReadVal(D); - SourceLocation RParenLoc = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - QualType ET = QualType::ReadVal(D); - return new ObjCEncodeExpr(T,ET,AtLoc,RParenLoc); -} - -void ObjCForCollectionStmt::EmitImpl(Serializer& S) const { - S.Emit(ForLoc); - S.Emit(RParenLoc); - S.BatchEmitOwnedPtrs(getElement(),getCollection(),getBody()); -} - -ObjCForCollectionStmt* ObjCForCollectionStmt::CreateImpl(Deserializer& D) { - SourceLocation ForLoc = SourceLocation::ReadVal(D); - SourceLocation RParenLoc = SourceLocation::ReadVal(D); - Stmt* Element; - Expr* Collection; - Stmt* Body; - D.BatchReadOwnedPtrs(Element,Collection,Body); - return new ObjCForCollectionStmt(Element,Collection,Body,ForLoc, RParenLoc); -} - -void ObjCIvarRefExpr::EmitImpl(Serializer& S) const { - S.Emit(Loc); - S.Emit(getType()); - S.EmitPtr(getDecl()); -} - -ObjCIvarRefExpr* ObjCIvarRefExpr::CreateImpl(Deserializer& D) { - SourceLocation Loc = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - ObjCIvarRefExpr* dr = new ObjCIvarRefExpr(NULL,T,Loc); - D.ReadPtr(dr->D,false); - return dr; -} - -void ObjCSelectorExpr::EmitImpl(Serializer& S) const { - S.Emit(AtLoc); - S.Emit(RParenLoc); - S.Emit(getType()); - S.Emit(SelName); -} - -ObjCSelectorExpr* ObjCSelectorExpr::CreateImpl(Deserializer& D) { - SourceLocation AtLoc = SourceLocation::ReadVal(D); - SourceLocation RParenLoc = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - Selector SelName = Selector::ReadVal(D); - - return new ObjCSelectorExpr(T,SelName,AtLoc,RParenLoc); -} - -void ObjCStringLiteral::EmitImpl(Serializer& S) const { - S.Emit(AtLoc); - S.Emit(getType()); - S.EmitOwnedPtr(String); -} - -ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D) { - SourceLocation L = SourceLocation::ReadVal(D); - QualType T = QualType::ReadVal(D); - StringLiteral* String = cast(D.ReadOwnedPtr()); - return new ObjCStringLiteral(String,T,L); -} diff --git a/clang/AST/StmtViz.cpp b/clang/AST/StmtViz.cpp deleted file mode 100644 index 51d514b20aa..00000000000 --- a/clang/AST/StmtViz.cpp +++ /dev/null @@ -1,59 +0,0 @@ -//===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements Stmt::viewAST, which generates a Graphviz DOT file -// that depicts the AST and then calls Graphviz/dot+gv on it. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/StmtGraphTraits.h" -#include "llvm/Support/GraphWriter.h" -#include - -using namespace clang; - -void Stmt::viewAST() const { -#ifndef NDEBUG - llvm::ViewGraph(this,"AST"); -#else - llvm::cerr << "Stmt::viewAST is only available in debug builds on " - << "systems with Graphviz or gv!\n"; -#endif -} - -namespace llvm { -template<> -struct DOTGraphTraits : public DefaultDOTGraphTraits { - static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) { - -#ifndef NDEBUG - std::ostringstream Out; - - if (Node) - Out << Node->getStmtClassName(); - else - Out << ""; - - std::string OutStr = Out.str(); - if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); - - // Process string output to make it nicer... - for (unsigned i = 0; i != OutStr.length(); ++i) - if (OutStr[i] == '\n') { // Left justify - OutStr[i] = '\\'; - OutStr.insert(OutStr.begin()+i+1, 'l'); - } - - return OutStr; -#else - return ""; -#endif - } -}; -} // end namespace llvm diff --git a/clang/AST/TranslationUnit.cpp b/clang/AST/TranslationUnit.cpp deleted file mode 100644 index b91448b2d3f..00000000000 --- a/clang/AST/TranslationUnit.cpp +++ /dev/null @@ -1,225 +0,0 @@ -//===--- TranslationUnit.cpp - Abstraction for Translation Units ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// FIXME: This should eventually be moved out of the driver, or replaced -// with its eventual successor. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/TranslationUnit.h" - -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/SourceManager.h" -#include "clang/AST/AST.h" - -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Path.h" -#include "llvm/ADT/OwningPtr.h" - -#include - -using namespace clang; - -enum { BasicMetadataBlock = 1, - ASTContextBlock = 2, - DeclsBlock = 3 }; - - -bool clang::EmitASTBitcodeFile(const TranslationUnit& TU, - const llvm::sys::Path& Filename) { - - // Reserve 256K for bitstream buffer. - std::vector Buffer; - Buffer.reserve(256*1024); - - // Create bitstream. - llvm::BitstreamWriter Stream(Buffer); - - // Emit the preamble. - Stream.Emit((unsigned)'B', 8); - Stream.Emit((unsigned)'C', 8); - Stream.Emit(0xC, 4); - Stream.Emit(0xF, 4); - Stream.Emit(0xE, 4); - Stream.Emit(0x0, 4); - - { - // Create serializer. Placing it in its own scope assures any necessary - // finalization of bits to the buffer in the serializer's dstor. - llvm::Serializer Sezr(Stream); - - // Emit the translation unit. - TU.Emit(Sezr); - } - - // Write the bits to disk. - if (FILE* fp = fopen(Filename.c_str(),"wb")) { - fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp); - fclose(fp); - return true; - } - - return false; -} - -void TranslationUnit::Emit(llvm::Serializer& Sezr) const { - - // ===---------------------------------------------------===/ - // Serialize the top-level decls. - // ===---------------------------------------------------===/ - - Sezr.EnterBlock(DeclsBlock); - - // Only serialize the head of a decl chain. The ASTConsumer interfaces - // provides us with each top-level decl, including those nested in - // a decl chain, so we may be passed decls that are already serialized. - for (const_iterator I=begin(), E=end(); I!=E; ++I) - if (!Sezr.isRegistered(*I)) - Sezr.EmitOwnedPtr(*I); - - Sezr.ExitBlock(); - - // ===---------------------------------------------------===/ - // Serialize the "Translation Unit" metadata. - // ===---------------------------------------------------===/ - - // Emit ASTContext. - Sezr.EnterBlock(ASTContextBlock); - Sezr.EmitOwnedPtr(Context); - Sezr.ExitBlock(); - - Sezr.EnterBlock(BasicMetadataBlock); - - // Block for SourceManager, LangOptions, and Target. Allows easy skipping - // around to the block for the Selectors during deserialization. - Sezr.EnterBlock(); - - // Emit the SourceManager. - Sezr.Emit(Context->getSourceManager()); - - // Emit the LangOptions. - Sezr.Emit(LangOpts); - - // Emit the Target. - Sezr.EmitPtr(&Context->Target); - Sezr.EmitCStr(Context->Target.getTargetTriple()); - - Sezr.ExitBlock(); // exit "BasicMetadataBlock" - - // Emit the Selectors. - Sezr.Emit(Context->Selectors); - - // Emit the Identifier Table. - Sezr.Emit(Context->Idents); - - Sezr.ExitBlock(); // exit "ASTContextBlock" -} - -TranslationUnit* -clang::ReadASTBitcodeFile(const llvm::sys::Path& Filename, FileManager& FMgr) { - - // Create the memory buffer that contains the contents of the file. - llvm::OwningPtr - MBuffer(llvm::MemoryBuffer::getFile(Filename.c_str(), - strlen(Filename.c_str()))); - - if (!MBuffer) { - // FIXME: Provide diagnostic. - return NULL; - } - - // Check if the file is of the proper length. - if (MBuffer->getBufferSize() & 0x3) { - // FIXME: Provide diagnostic: "Length should be a multiple of 4 bytes." - return NULL; - } - - // Create the bitstream reader. - unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart(); - llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize()); - - if (Stream.Read(8) != 'B' || - Stream.Read(8) != 'C' || - Stream.Read(4) != 0xC || - Stream.Read(4) != 0xF || - Stream.Read(4) != 0xE || - Stream.Read(4) != 0x0) { - // FIXME: Provide diagnostic. - return NULL; - } - - // Create the deserializer. - llvm::Deserializer Dezr(Stream); - - return TranslationUnit::Create(Dezr,FMgr); -} - -TranslationUnit* TranslationUnit::Create(llvm::Deserializer& Dezr, - FileManager& FMgr) { - - // Create the translation unit object. - TranslationUnit* TU = new TranslationUnit(); - - // ===---------------------------------------------------===/ - // Deserialize the "Translation Unit" metadata. - // ===---------------------------------------------------===/ - - // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock - // (which will appear earlier) and record its location. - - bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock); - assert (FoundBlock); - - llvm::Deserializer::Location ASTContextBlockLoc = - Dezr.getCurrentBlockLocation(); - - FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock); - assert (FoundBlock); - - // Read the SourceManager. - SourceManager::CreateAndRegister(Dezr,FMgr); - - // Read the LangOptions. - TU->LangOpts.Read(Dezr); - - { // Read the TargetInfo. - llvm::SerializedPtrID PtrID = Dezr.ReadPtrID(); - char* triple = Dezr.ReadCStr(NULL,0,true); - Dezr.RegisterPtr(PtrID,TargetInfo::CreateTargetInfo(std::string(triple))); - delete [] triple; - } - - // For Selectors, we must read the identifier table first because the - // SelectorTable depends on the identifiers being already deserialized. - llvm::Deserializer::Location SelectorBlkLoc = Dezr.getCurrentBlockLocation(); - Dezr.SkipBlock(); - - // Read the identifier table. - IdentifierTable::CreateAndRegister(Dezr); - - // Now jump back and read the selectors. - Dezr.JumpTo(SelectorBlkLoc); - SelectorTable::CreateAndRegister(Dezr); - - // Now jump back to ASTContextBlock and read the ASTContext. - Dezr.JumpTo(ASTContextBlockLoc); - TU->Context = Dezr.ReadOwnedPtr(); - - // "Rewind" the stream. Find the block with the serialized top-level decls. - Dezr.Rewind(); - FoundBlock = Dezr.SkipToBlock(DeclsBlock); - assert (FoundBlock); - llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation(); - - while (!Dezr.FinishedBlock(DeclBlockLoc)) - TU->AddTopLevelDecl(Dezr.ReadOwnedPtr()); - - return TU; -} - diff --git a/clang/AST/Type.cpp b/clang/AST/Type.cpp deleted file mode 100644 index 80b2d5cb93d..00000000000 --- a/clang/AST/Type.cpp +++ /dev/null @@ -1,978 +0,0 @@ -//===--- Type.cpp - Type representation and manipulation ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements type-related functionality. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Type.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/Expr.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/Support/Streams.h" -#include "llvm/ADT/StringExtras.h" -#include - -using namespace clang; - -Type::~Type() {} - -/// isVoidType - Helper method to determine if this is the 'void' type. -bool Type::isVoidType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Void; - return false; -} - -bool Type::isObjectType() const { - if (isa(CanonicalType)) - return false; - else if (CanonicalType->isIncompleteType()) - return false; - else - return true; -} - -bool Type::isDerivedType() const { - switch (CanonicalType->getTypeClass()) { - case Pointer: - case VariableArray: - case ConstantArray: - case IncompleteArray: - case FunctionProto: - case FunctionNoProto: - case Reference: - return true; - case Tagged: { - const TagType *TT = cast(CanonicalType); - const Decl::Kind Kind = TT->getDecl()->getKind(); - return Kind == Decl::Struct || Kind == Decl::Union; - } - default: - return false; - } -} - -bool Type::isStructureType() const { - if (const RecordType *RT = dyn_cast(CanonicalType)) - if (RT->getDecl()->getKind() == Decl::Struct) - return true; - return false; -} -bool Type::isUnionType() const { - if (const RecordType *RT = dyn_cast(CanonicalType)) - if (RT->getDecl()->getKind() == Decl::Union) - return true; - return false; -} - -bool Type::isComplexType() const { - if (const ComplexType *CT = dyn_cast(CanonicalType)) - return CT->getElementType()->isFloatingType(); - return false; -} - -bool Type::isComplexIntegerType() const { - // Check for GCC complex integer extension. - if (const ComplexType *CT = dyn_cast(CanonicalType)) - return CT->getElementType()->isIntegerType(); - return false; -} - -const ComplexType *Type::getAsComplexIntegerType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast(this)) { - if (CTy->getElementType()->isIntegerType()) - return CTy; - } - // If the canonical form of this type isn't the right kind, reject it. - const ComplexType *CTy = dyn_cast(CanonicalType); - if (!CTy || !CTy->getElementType()->isIntegerType()) - return 0; - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsComplexIntegerType(); -} - -/// getDesugaredType - Return the specified type with any "sugar" removed from -/// type type. This takes off typedefs, typeof's etc. If the outer level of -/// the type is already concrete, it returns it unmodified. This is similar -/// to getting the canonical type, but it doesn't remove *all* typedefs. For -/// example, it return "T*" as "T*", (not as "int*"), because the pointer is -/// concrete. -const Type *Type::getDesugaredType() const { - if (const TypedefType *TDT = dyn_cast(this)) - return TDT->LookThroughTypedefs().getTypePtr(); - if (const TypeOfExpr *TOE = dyn_cast(this)) - return TOE->getUnderlyingExpr()->getType().getTypePtr(); - if (const TypeOfType *TOT = dyn_cast(this)) - return TOT->getUnderlyingType().getTypePtr(); - return this; -} - - -const BuiltinType *Type::getAsBuiltinType() const { - // If this is directly a builtin type, return it. - if (const BuiltinType *BTy = dyn_cast(this)) - return BTy; - - // If the canonical form of this type isn't a builtin type, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsBuiltinType(); - return 0; - } - - // If this is a typedef for a builtin type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsBuiltinType(); -} - -const FunctionType *Type::getAsFunctionType() const { - // If this is directly a function type, return it. - if (const FunctionType *FTy = dyn_cast(this)) - return FTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsFunctionType(); - return 0; - } - - // If this is a typedef for a function type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsFunctionType(); -} - -const PointerType *Type::getAsPointerType() const { - // If this is directly a pointer type, return it. - if (const PointerType *PTy = dyn_cast(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsPointerType(); - return 0; - } - - // If this is a typedef for a pointer type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsPointerType(); -} - -const ReferenceType *Type::getAsReferenceType() const { - // If this is directly a reference type, return it. - if (const ReferenceType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsReferenceType(); - return 0; - } - - // If this is a typedef for a reference type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsReferenceType(); -} - -const ArrayType *Type::getAsArrayType() const { - // If this is directly an array type, return it. - if (const ArrayType *ATy = dyn_cast(this)) - return ATy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsArrayType(); - return 0; - } - - // If this is a typedef for an array type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsArrayType(); -} - -const ConstantArrayType *Type::getAsConstantArrayType() const { - // If this is directly a constant array type, return it. - if (const ConstantArrayType *ATy = dyn_cast(this)) - return ATy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsConstantArrayType(); - return 0; - } - - // If this is a typedef for a constant array type, strip the typedef off - // without losing all typedef information. - return getDesugaredType()->getAsConstantArrayType(); -} - -const VariableArrayType *Type::getAsVariableArrayType() const { - // If this is directly a variable array type, return it. - if (const VariableArrayType *ATy = dyn_cast(this)) - return ATy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsVariableArrayType(); - return 0; - } - - // If this is a typedef for a variable array type, strip the typedef off - // without losing all typedef information. - return getDesugaredType()->getAsVariableArrayType(); -} - -/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length -/// array types and types that contain variable array types in their -/// declarator -bool Type::isVariablyModifiedType() const { - // A VLA is a veriably modified type - if (getAsVariableArrayType()) - return true; - - // An array can contain a variably modified type - if (const ArrayType* AT = getAsArrayType()) - return AT->getElementType()->isVariablyModifiedType(); - - // A pointer can point to a variably modified type - if (const PointerType* PT = getAsPointerType()) - return PT->getPointeeType()->isVariablyModifiedType(); - - // A function can return a variably modified type - // This one isn't completely obvious, but it follows from the - // definition in C99 6.7.5p3. Because of this rule, it's - // illegal to declare a function returning a variably modified type. - if (const FunctionType* FT = getAsFunctionType()) - return FT->getResultType()->isVariablyModifiedType(); - - return false; -} - -bool Type::isIncompleteArrayType() const { - return isa(CanonicalType); -} - -const IncompleteArrayType *Type::getAsIncompleteArrayType() const { - // If this is directly a variable array type, return it. - if (const IncompleteArrayType *ATy = dyn_cast(this)) - return ATy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsIncompleteArrayType(); - return 0; - } - - // If this is a typedef for a variable array type, strip the typedef off - // without losing all typedef information. - return getDesugaredType()->getAsIncompleteArrayType(); -} - -const RecordType *Type::getAsRecordType() const { - // If this is directly a reference type, return it. - if (const RecordType *RTy = dyn_cast(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsRecordType(); - return 0; - } - - // If this is a typedef for a record type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsRecordType(); -} - -const RecordType *Type::getAsStructureType() const { - // If this is directly a structure type, return it. - if (const RecordType *RT = dyn_cast(this)) { - if (RT->getDecl()->getKind() == Decl::Struct) - return RT; - } - - // If the canonical form of this type isn't the right kind, reject it. - if (const RecordType *RT = dyn_cast(CanonicalType)) { - if (RT->getDecl()->getKind() != Decl::Struct) - return 0; - - // If this is a typedef for a structure type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsStructureType(); - } - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsStructureType(); - return 0; -} - -const RecordType *Type::getAsUnionType() const { - // If this is directly a union type, return it. - if (const RecordType *RT = dyn_cast(this)) { - if (RT->getDecl()->getKind() == Decl::Union) - return RT; - } - - // If the canonical form of this type isn't the right kind, reject it. - if (const RecordType *RT = dyn_cast(CanonicalType)) { - if (RT->getDecl()->getKind() != Decl::Union) - return 0; - - // If this is a typedef for a union type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsUnionType(); - } - - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsUnionType(); - return 0; -} - -const ComplexType *Type::getAsComplexType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast(this)) - return CTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsComplexType(); - return 0; - } - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsComplexType(); -} - -const VectorType *Type::getAsVectorType() const { - // Are we directly a vector type? - if (const VectorType *VTy = dyn_cast(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsVectorType(); - return 0; - } - - // If this is a typedef for a vector type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsVectorType(); -} - -const OCUVectorType *Type::getAsOCUVectorType() const { - // Are we directly an OpenCU vector type? - if (const OCUVectorType *VTy = dyn_cast(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsOCUVectorType(); - return 0; - } - - // If this is a typedef for an ocuvector type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsOCUVectorType(); -} - -bool Type::isIntegerType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::LongLong; - if (const TagType *TT = dyn_cast(CanonicalType)) - if (TT->getDecl()->getKind() == Decl::Enum) - return true; - if (const VectorType *VT = dyn_cast(CanonicalType)) - return VT->getElementType()->isIntegerType(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isIntegerType(); - return false; -} - -bool Type::isIntegralType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::LongLong; - if (const TagType *TT = dyn_cast(CanonicalType)) - if (TT->getDecl()->getKind() == Decl::Enum) - return true; - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isIntegralType(); - return false; -} - -bool Type::isEnumeralType() const { - if (const TagType *TT = dyn_cast(CanonicalType)) - return TT->getDecl()->getKind() == Decl::Enum; - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isEnumeralType(); - return false; -} - -bool Type::isBooleanType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Bool; - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isBooleanType(); - return false; -} - -bool Type::isCharType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Char_U || - BT->getKind() == BuiltinType::UChar || - BT->getKind() == BuiltinType::Char_S || - BT->getKind() == BuiltinType::SChar; - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isCharType(); - return false; -} - -/// isSignedIntegerType - Return true if this is an integer type that is -/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], -/// an enum decl which has a signed representation, or a vector of signed -/// integer element type. -bool Type::isSignedIntegerType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) { - return BT->getKind() >= BuiltinType::Char_S && - BT->getKind() <= BuiltinType::LongLong; - } - - if (const TagType *TT = dyn_cast(CanonicalType)) - if (const EnumDecl *ED = dyn_cast(TT->getDecl())) - return ED->getIntegerType()->isSignedIntegerType(); - - if (const VectorType *VT = dyn_cast(CanonicalType)) - return VT->getElementType()->isSignedIntegerType(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isSignedIntegerType(); - return false; -} - -/// isUnsignedIntegerType - Return true if this is an integer type that is -/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum -/// decl which has an unsigned representation, or a vector of unsigned integer -/// element type. -bool Type::isUnsignedIntegerType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) { - return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::ULongLong; - } - - if (const TagType *TT = dyn_cast(CanonicalType)) - if (const EnumDecl *ED = dyn_cast(TT->getDecl())) - return ED->getIntegerType()->isUnsignedIntegerType(); - - if (const VectorType *VT = dyn_cast(CanonicalType)) - return VT->getElementType()->isUnsignedIntegerType(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isUnsignedIntegerType(); - return false; -} - -bool Type::isFloatingType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Float && - BT->getKind() <= BuiltinType::LongDouble; - if (const ComplexType *CT = dyn_cast(CanonicalType)) - return CT->getElementType()->isFloatingType(); - if (const VectorType *VT = dyn_cast(CanonicalType)) - return VT->getElementType()->isFloatingType(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isFloatingType(); - return false; -} - -bool Type::isRealFloatingType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Float && - BT->getKind() <= BuiltinType::LongDouble; - if (const VectorType *VT = dyn_cast(CanonicalType)) - return VT->getElementType()->isRealFloatingType(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isRealFloatingType(); - return false; -} - -bool Type::isRealType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::LongDouble; - if (const TagType *TT = dyn_cast(CanonicalType)) - return TT->getDecl()->getKind() == Decl::Enum; - if (const VectorType *VT = dyn_cast(CanonicalType)) - return VT->getElementType()->isRealType(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isRealType(); - return false; -} - -bool Type::isArithmeticType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() != BuiltinType::Void; - if (const TagType *TT = dyn_cast(CanonicalType)) - if (const EnumDecl *ED = dyn_cast(TT->getDecl())) - // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). - // If a body isn't seen by the time we get here, return false. - return ED->isDefinition(); - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isArithmeticType(); - return isa(CanonicalType) || isa(CanonicalType); -} - -bool Type::isScalarType() const { - if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() != BuiltinType::Void; - if (const TagType *TT = dyn_cast(CanonicalType)) { - if (TT->getDecl()->getKind() == Decl::Enum) - return true; - return false; - } - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isScalarType(); - return isa(CanonicalType) || isa(CanonicalType) || - isa(CanonicalType); -} - -bool Type::isAggregateType() const { - if (const TagType *TT = dyn_cast(CanonicalType)) { - if (TT->getDecl()->getKind() == Decl::Struct) - return true; - return false; - } - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isAggregateType(); - return isa(CanonicalType); -} - -/// isConstantSizeType - Return true if this is not a variable sized type, -/// according to the rules of C99 6.7.5p3. It is not legal to call this on -/// incomplete types. -bool Type::isConstantSizeType() const { - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isConstantSizeType(); - assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); - // The VAT must have a size, as it is known to be complete. - return !isa(CanonicalType); -} - -/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) -/// - a type that can describe objects, but which lacks information needed to -/// determine its size. -bool Type::isIncompleteType() const { - switch (CanonicalType->getTypeClass()) { - default: return false; - case ASQual: - return cast(CanonicalType)->getBaseType()->isIncompleteType(); - case Builtin: - // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never - // be completed. - return isVoidType(); - case Tagged: - // A tagged type (struct/union/enum/class) is incomplete if the decl is a - // forward declaration, but not a full definition (C99 6.2.5p22). - return !cast(CanonicalType)->getDecl()->isDefinition(); - case IncompleteArray: - // An array of unknown size is an incomplete type (C99 6.2.5p22). - return true; - } -} - -bool Type::isPromotableIntegerType() const { - if (const ASQualType *ASQT = dyn_cast(CanonicalType)) - return ASQT->getBaseType()->isPromotableIntegerType(); - const BuiltinType *BT = dyn_cast(CanonicalType); - if (!BT) return false; - switch (BT->getKind()) { - case BuiltinType::Bool: - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - case BuiltinType::Short: - case BuiltinType::UShort: - return true; - default: - return false; - } -} - -const char *BuiltinType::getName() const { - switch (getKind()) { - default: assert(0 && "Unknown builtin type!"); - case Void: return "void"; - case Bool: return "_Bool"; - case Char_S: return "char"; - case Char_U: return "char"; - case SChar: return "signed char"; - case Short: return "short"; - case Int: return "int"; - case Long: return "long"; - case LongLong: return "long long"; - case UChar: return "unsigned char"; - case UShort: return "unsigned short"; - case UInt: return "unsigned int"; - case ULong: return "unsigned long"; - case ULongLong: return "unsigned long long"; - case Float: return "float"; - case Double: return "double"; - case LongDouble: return "long double"; - } -} - -void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result, - arg_type_iterator ArgTys, - unsigned NumArgs, bool isVariadic) { - ID.AddPointer(Result.getAsOpaquePtr()); - for (unsigned i = 0; i != NumArgs; ++i) - ID.AddPointer(ArgTys[i].getAsOpaquePtr()); - ID.AddInteger(isVariadic); -} - -void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic()); -} - -void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, - ObjCProtocolDecl **protocols, - unsigned NumProtocols) { - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(protocols[i]); -} - -void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, &Protocols[0], getNumProtocols()); -} - -void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID, - ObjCProtocolDecl **protocols, - unsigned NumProtocols) { - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(protocols[i]); -} - -void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, &Protocols[0], getNumProtocols()); -} - -/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to -/// potentially looking through *all* consequtive typedefs. This returns the -/// sum of the type qualifiers, so if you have: -/// typedef const int A; -/// typedef volatile A B; -/// looking through the typedefs for B will give you "const volatile A". -/// -QualType TypedefType::LookThroughTypedefs() const { - // Usually, there is only a single level of typedefs, be fast in that case. - QualType FirstType = getDecl()->getUnderlyingType(); - if (!isa(FirstType)) - return FirstType; - - // Otherwise, do the fully general loop. - unsigned TypeQuals = 0; - const TypedefType *TDT = this; - while (1) { - QualType CurType = TDT->getDecl()->getUnderlyingType(); - - - /// FIXME: - /// FIXME: This is incorrect for ASQuals! - /// FIXME: - TypeQuals |= CurType.getCVRQualifiers(); - - TDT = dyn_cast(CurType); - if (TDT == 0) - return QualType(CurType.getTypePtr(), TypeQuals); - } -} - -bool RecordType::classof(const Type *T) { - if (const TagType *TT = dyn_cast(T)) - return isa(TT->getDecl()); - return false; -} - - -//===----------------------------------------------------------------------===// -// Type Printing -//===----------------------------------------------------------------------===// - -void QualType::dump(const char *msg) const { - std::string R = "identifier"; - getAsStringInternal(R); - if (msg) - fprintf(stderr, "%s: %s\n", msg, R.c_str()); - else - fprintf(stderr, "%s\n", R.c_str()); -} - -static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { - // Note: funkiness to ensure we get a space only between quals. - bool NonePrinted = true; - if (TypeQuals & QualType::Const) - S += "const", NonePrinted = false; - if (TypeQuals & QualType::Volatile) - S += (NonePrinted+" volatile"), NonePrinted = false; - if (TypeQuals & QualType::Restrict) - S += (NonePrinted+" restrict"), NonePrinted = false; -} - -void QualType::getAsStringInternal(std::string &S) const { - if (isNull()) { - S += "NULL TYPE\n"; - return; - } - - // Print qualifiers as appropriate. - if (unsigned Tq = getCVRQualifiers()) { - std::string TQS; - AppendTypeQualList(TQS, Tq); - if (!S.empty()) - S = TQS + ' ' + S; - else - S = TQS; - } - - getTypePtr()->getAsStringInternal(S); -} - -void BuiltinType::getAsStringInternal(std::string &S) const { - if (S.empty()) { - S = getName(); - } else { - // Prefix the basic type, e.g. 'int X'. - S = ' ' + S; - S = getName() + S; - } -} - -void ComplexType::getAsStringInternal(std::string &S) const { - ElementType->getAsStringInternal(S); - S = "_Complex " + S; -} - -void ASQualType::getAsStringInternal(std::string &S) const { - S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; - BaseType->getAsStringInternal(S); -} - -void PointerType::getAsStringInternal(std::string &S) const { - S = '*' + S; - - // Handle things like 'int (*A)[4];' correctly. - // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa(PointeeType.getTypePtr())) - S = '(' + S + ')'; - - PointeeType.getAsStringInternal(S); -} - -void ReferenceType::getAsStringInternal(std::string &S) const { - S = '&' + S; - - // Handle things like 'int (&A)[4];' correctly. - // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa(ReferenceeType.getTypePtr())) - S = '(' + S + ')'; - - ReferenceeType.getAsStringInternal(S); -} - -void ConstantArrayType::getAsStringInternal(std::string &S) const { - S += '['; - S += llvm::utostr(getSize().getZExtValue()); - S += ']'; - - getElementType().getAsStringInternal(S); -} - -void IncompleteArrayType::getAsStringInternal(std::string &S) const { - S += "[]"; - - getElementType().getAsStringInternal(S); -} - -void VariableArrayType::getAsStringInternal(std::string &S) const { - S += '['; - - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); - S += ' '; - } - - if (getSizeModifier() == Static) - S += "static"; - else if (getSizeModifier() == Star) - S += '*'; - - if (getSizeExpr()) { - std::ostringstream s; - getSizeExpr()->printPretty(s); - S += s.str(); - } - S += ']'; - - getElementType().getAsStringInternal(S); -} - -void VectorType::getAsStringInternal(std::string &S) const { - S += " __attribute__((__vector_size__("; - // FIXME: should multiply by element size somehow. - S += llvm::utostr_32(NumElements*4); // convert back to bytes. - S += ")))"; - ElementType.getAsStringInternal(S); -} - -void OCUVectorType::getAsStringInternal(std::string &S) const { - S += " __attribute__((ocu_vector_type("; - S += llvm::utostr_32(NumElements); - S += ")))"; - ElementType.getAsStringInternal(S); -} - -void TypeOfExpr::getAsStringInternal(std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. - InnerString = ' ' + InnerString; - std::ostringstream s; - getUnderlyingExpr()->printPretty(s); - InnerString = "typeof(" + s.str() + ")" + InnerString; -} - -void TypeOfType::getAsStringInternal(std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. - InnerString = ' ' + InnerString; - std::string Tmp; - getUnderlyingType().getAsStringInternal(Tmp); - InnerString = "typeof(" + Tmp + ")" + InnerString; -} - -void FunctionTypeNoProto::getAsStringInternal(std::string &S) const { - // If needed for precedence reasons, wrap the inner part in grouping parens. - if (!S.empty()) - S = "(" + S + ")"; - - S += "()"; - getResultType().getAsStringInternal(S); -} - -void FunctionTypeProto::getAsStringInternal(std::string &S) const { - // If needed for precedence reasons, wrap the inner part in grouping parens. - if (!S.empty()) - S = "(" + S + ")"; - - S += "("; - std::string Tmp; - for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { - if (i) S += ", "; - getArgType(i).getAsStringInternal(Tmp); - S += Tmp; - Tmp.clear(); - } - - if (isVariadic()) { - if (getNumArgs()) - S += ", "; - S += "..."; - } else if (getNumArgs() == 0) { - // Do not emit int() if we have a proto, emit 'int(void)'. - S += "void"; - } - - S += ")"; - getResultType().getAsStringInternal(S); -} - - -void TypedefType::getAsStringInternal(std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName() + InnerString; -} - -void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName() + InnerString; -} - -void ObjCQualifiedInterfaceType::getAsStringInternal( - std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - std::string ObjCQIString = getDecl()->getName(); - ObjCQIString += '<'; - int num = getNumProtocols(); - for (int i = 0; i < num; i++) { - ObjCQIString += getProtocols(i)->getName(); - if (i < num-1) - ObjCQIString += ','; - } - ObjCQIString += '>'; - InnerString = ObjCQIString + InnerString; -} - -void ObjCQualifiedIdType::getAsStringInternal( - std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - std::string ObjCQIString = "id"; - ObjCQIString += '<'; - int num = getNumProtocols(); - for (int i = 0; i < num; i++) { - ObjCQIString += getProtocols(i)->getName(); - if (i < num-1) - ObjCQIString += ','; - } - ObjCQIString += '>'; - InnerString = ObjCQIString + InnerString; -} - -void TagType::getAsStringInternal(std::string &InnerString) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - const char *Kind = getDecl()->getKindName(); - const char *ID; - if (const IdentifierInfo *II = getDecl()->getIdentifier()) - ID = II->getName(); - else - ID = ""; - - InnerString = std::string(Kind) + " " + ID + InnerString; -} diff --git a/clang/AST/TypeSerialization.cpp b/clang/AST/TypeSerialization.cpp deleted file mode 100644 index 55c0a48a00d..00000000000 --- a/clang/AST/TypeSerialization.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===--- TypeSerialization.cpp - Serialization of Decls ---------*- 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 methods that implement bitcode serialization for Types. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Type.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ASTContext.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using namespace clang; -using llvm::Serializer; -using llvm::Deserializer; -using llvm::SerializedPtrID; - - -void QualType::Emit(Serializer& S) const { - S.EmitPtr(getTypePtr()); - S.EmitInt(getCVRQualifiers()); -} - -QualType QualType::ReadVal(Deserializer& D) { - QualType Q; - D.ReadUIntPtr(Q.ThePtr,false); - Q.ThePtr |= D.ReadInt(); - return Q; -} - -void QualType::ReadBackpatch(Deserializer& D) { - D.ReadUIntPtr(ThePtr,true); - ThePtr |= D.ReadInt(); -} - -//===----------------------------------------------------------------------===// -// Type Serialization: Dispatch code to handle specific types. -//===----------------------------------------------------------------------===// - -void Type::Emit(Serializer& S) const { - S.EmitInt(getTypeClass()); - S.EmitPtr(this); - - if (!isa(this)) - EmitImpl(S); -} - -void Type::EmitImpl(Serializer& S) const { - assert (false && "Serializization for type not supported."); -} - -void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { - Type::TypeClass K = static_cast(D.ReadInt()); - SerializedPtrID PtrID = D.ReadPtrID(); - - switch (K) { - default: - assert (false && "Deserialization for type not supported."); - break; - - case Type::Builtin: - assert (i < Context.getTypes().size()); - assert (isa(Context.getTypes()[i])); - D.RegisterPtr(PtrID,Context.getTypes()[i]); - break; - - case Type::ASQual: - D.RegisterPtr(PtrID,ASQualType::CreateImpl(Context,D)); - break; - - case Type::Complex: - D.RegisterPtr(PtrID,ComplexType::CreateImpl(Context,D)); - break; - - case Type::ConstantArray: - D.RegisterPtr(PtrID,ConstantArrayType::CreateImpl(Context,D)); - break; - - case Type::FunctionNoProto: - D.RegisterPtr(PtrID,FunctionTypeNoProto::CreateImpl(Context,D)); - break; - - case Type::FunctionProto: - D.RegisterPtr(PtrID,FunctionTypeProto::CreateImpl(Context,D)); - break; - - case Type::IncompleteArray: - D.RegisterPtr(PtrID,IncompleteArrayType::CreateImpl(Context,D)); - break; - - case Type::Pointer: - D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D)); - break; - - case Type::Tagged: - D.RegisterPtr(PtrID,TagType::CreateImpl(Context,D)); - break; - - case Type::TypeName: - D.RegisterPtr(PtrID,TypedefType::CreateImpl(Context,D)); - break; - - case Type::VariableArray: - D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D)); - break; - } -} - -//===----------------------------------------------------------------------===// -// ASQualType -//===----------------------------------------------------------------------===// - -void ASQualType::EmitImpl(Serializer& S) const { - S.EmitPtr(getBaseType()); - S.EmitInt(getAddressSpace()); -} - -Type* ASQualType::CreateImpl(ASTContext& Context, Deserializer& D) { - QualType BaseTy = QualType::ReadVal(D); - unsigned AddressSpace = D.ReadInt(); - return Context.getASQualType(BaseTy, AddressSpace).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// ComplexType -//===----------------------------------------------------------------------===// - -void ComplexType::EmitImpl(Serializer& S) const { - S.Emit(getElementType()); -} - -Type* ComplexType::CreateImpl(ASTContext& Context, Deserializer& D) { - return Context.getComplexType(QualType::ReadVal(D)).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// ConstantArray -//===----------------------------------------------------------------------===// - -void ConstantArrayType::EmitImpl(Serializer& S) const { - S.Emit(getElementType()); - S.EmitInt(getSizeModifier()); - S.EmitInt(getIndexTypeQualifier()); - S.Emit(Size); -} - -Type* ConstantArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { - QualType ElTy = QualType::ReadVal(D); - ArraySizeModifier am = static_cast(D.ReadInt()); - unsigned ITQ = D.ReadInt(); - - llvm::APInt Size; - D.Read(Size); - - return Context.getConstantArrayType(ElTy,Size,am,ITQ).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// FunctionTypeNoProto -//===----------------------------------------------------------------------===// - -void FunctionTypeNoProto::EmitImpl(Serializer& S) const { - S.Emit(getResultType()); -} - -Type* FunctionTypeNoProto::CreateImpl(ASTContext& Context, Deserializer& D) { - return Context.getFunctionTypeNoProto(QualType::ReadVal(D)).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// FunctionTypeProto -//===----------------------------------------------------------------------===// - -void FunctionTypeProto::EmitImpl(Serializer& S) const { - S.Emit(getResultType()); - S.EmitBool(isVariadic()); - S.EmitInt(getNumArgs()); - - for (arg_type_iterator I=arg_type_begin(), E=arg_type_end(); I!=E; ++I) - S.Emit(*I); -} - -Type* FunctionTypeProto::CreateImpl(ASTContext& Context, Deserializer& D) { - QualType ResultType = QualType::ReadVal(D); - bool isVariadic = D.ReadBool(); - unsigned NumArgs = D.ReadInt(); - - llvm::SmallVector Args; - - for (unsigned j = 0; j < NumArgs; ++j) - Args.push_back(QualType::ReadVal(D)); - - return Context.getFunctionType(ResultType,&*Args.begin(), - NumArgs,isVariadic).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// PointerType -//===----------------------------------------------------------------------===// - -void PointerType::EmitImpl(Serializer& S) const { - S.Emit(getPointeeType()); -} - -Type* PointerType::CreateImpl(ASTContext& Context, Deserializer& D) { - return Context.getPointerType(QualType::ReadVal(D)).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// TagType -//===----------------------------------------------------------------------===// - -void TagType::EmitImpl(Serializer& S) const { - S.EmitOwnedPtr(getDecl()); -} - -Type* TagType::CreateImpl(ASTContext& Context, Deserializer& D) { - std::vector& Types = - const_cast&>(Context.getTypes()); - - TagType* T = new TagType(NULL,QualType()); - Types.push_back(T); - - // Deserialize the decl. - T->decl = cast(D.ReadOwnedPtr()); - - return T; -} - -//===----------------------------------------------------------------------===// -// TypedefType -//===----------------------------------------------------------------------===// - -void TypedefType::EmitImpl(Serializer& S) const { - S.Emit(QualType((Type*)this,0).getCanonicalType()); - S.EmitPtr(Decl); -} - -Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) { - std::vector& Types = - const_cast&>(Context.getTypes()); - - TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D)); - Types.push_back(T); - - D.ReadPtr(T->Decl); // May be backpatched. - return T; -} - -//===----------------------------------------------------------------------===// -// VariableArrayType -//===----------------------------------------------------------------------===// - -void VariableArrayType::EmitImpl(Serializer& S) const { - S.Emit(getElementType()); - S.EmitInt(getSizeModifier()); - S.EmitInt(getIndexTypeQualifier()); - S.EmitOwnedPtr(SizeExpr); -} - -Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { - QualType ElTy = QualType::ReadVal(D); - ArraySizeModifier am = static_cast(D.ReadInt()); - unsigned ITQ = D.ReadInt(); - Expr* SizeExpr = D.ReadOwnedPtr(); - - return Context.getVariableArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr(); -} - -//===----------------------------------------------------------------------===// -// IncompleteArrayType -//===----------------------------------------------------------------------===// - -void IncompleteArrayType::EmitImpl(Serializer& S) const { - S.Emit(getElementType()); - S.EmitInt(getSizeModifier()); - S.EmitInt(getIndexTypeQualifier()); -} - -Type* IncompleteArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { - QualType ElTy = QualType::ReadVal(D); - ArraySizeModifier am = static_cast(D.ReadInt()); - unsigned ITQ = D.ReadInt(); - - return Context.getIncompleteArrayType(ElTy,am,ITQ).getTypePtr(); -} diff --git a/clang/Analysis/BasicValueFactory.cpp b/clang/Analysis/BasicValueFactory.cpp deleted file mode 100644 index 88b360d1d0e..00000000000 --- a/clang/Analysis/BasicValueFactory.cpp +++ /dev/null @@ -1,167 +0,0 @@ -//=== BasicValueFactory.cpp - Basic values for Path Sens analysis --*- 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 BasicValueFactory, a class that manages the lifetime -// of APSInt objects and symbolic constraints used by GRExprEngine -// and related classes. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/BasicValueFactory.h" - -using namespace clang; - -BasicValueFactory::~BasicValueFactory() { - // Note that the dstor for the contents of APSIntSet will never be called, - // so we iterate over the set and invoke the dstor for each APSInt. This - // frees an aux. memory allocated to represent very large constants. - for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I) - I->getValue().~APSInt(); -} - -const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { - llvm::FoldingSetNodeID ID; - void* InsertPos; - typedef llvm::FoldingSetNodeWrapper FoldNodeTy; - - X.Profile(ID); - FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); - - if (!P) { - P = (FoldNodeTy*) BPAlloc.Allocate(); - new (P) FoldNodeTy(X); - APSIntSet.InsertNode(P, InsertPos); - } - - return *P; -} - -const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, - bool isUnsigned) { - llvm::APSInt V(BitWidth, isUnsigned); - V = X; - return getValue(V); -} - -const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { - - unsigned bits = Ctx.getTypeSize(T); - llvm::APSInt V(bits, T->isUnsignedIntegerType()); - V = X; - return getValue(V); -} - -const SymIntConstraint& -BasicValueFactory::getConstraint(SymbolID sym, BinaryOperator::Opcode Op, - const llvm::APSInt& V) { - - llvm::FoldingSetNodeID ID; - SymIntConstraint::Profile(ID, sym, Op, V); - void* InsertPos; - - SymIntConstraint* C = SymIntCSet.FindNodeOrInsertPos(ID, InsertPos); - - if (!C) { - C = (SymIntConstraint*) BPAlloc.Allocate(); - new (C) SymIntConstraint(sym, Op, V); - SymIntCSet.InsertNode(C, InsertPos); - } - - return *C; -} - -const llvm::APSInt* -BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, - const llvm::APSInt& V1, const llvm::APSInt& V2) { - - switch (Op) { - default: - assert (false && "Invalid Opcode."); - - case BinaryOperator::Mul: - return &getValue( V1 * V2 ); - - case BinaryOperator::Div: - return &getValue( V1 / V2 ); - - case BinaryOperator::Rem: - return &getValue( V1 % V2 ); - - case BinaryOperator::Add: - return &getValue( V1 + V2 ); - - case BinaryOperator::Sub: - return &getValue( V1 - V2 ); - - case BinaryOperator::Shl: { - - // FIXME: This logic should probably go higher up, where we can - // test these conditions symbolically. - - // FIXME: Expand these checks to include all undefined behavior. - - if (V2.isSigned() && V2.isNegative()) - return NULL; - - uint64_t Amt = V2.getZExtValue(); - - if (Amt > V1.getBitWidth()) - return NULL; - - return &getValue( V1.operator<<( (unsigned) Amt )); - } - - case BinaryOperator::Shr: { - - // FIXME: This logic should probably go higher up, where we can - // test these conditions symbolically. - - // FIXME: Expand these checks to include all undefined behavior. - - if (V2.isSigned() && V2.isNegative()) - return NULL; - - uint64_t Amt = V2.getZExtValue(); - - if (Amt > V1.getBitWidth()) - return NULL; - - return &getValue( V1.operator>>( (unsigned) Amt )); - } - - case BinaryOperator::LT: - return &getTruthValue( V1 < V2 ); - - case BinaryOperator::GT: - return &getTruthValue( V1 > V2 ); - - case BinaryOperator::LE: - return &getTruthValue( V1 <= V2 ); - - case BinaryOperator::GE: - return &getTruthValue( V1 >= V2 ); - - case BinaryOperator::EQ: - return &getTruthValue( V1 == V2 ); - - case BinaryOperator::NE: - return &getTruthValue( V1 != V2 ); - - // Note: LAnd, LOr, Comma are handled specially by higher-level logic. - - case BinaryOperator::And: - return &getValue( V1 & V2 ); - - case BinaryOperator::Or: - return &getValue( V1 | V2 ); - - case BinaryOperator::Xor: - return &getValue( V1 ^ V2 ); - } -} diff --git a/clang/Analysis/CFRefCount.cpp b/clang/Analysis/CFRefCount.cpp deleted file mode 100644 index 5088ff7ecbf..00000000000 --- a/clang/Analysis/CFRefCount.cpp +++ /dev/null @@ -1,796 +0,0 @@ -// CFRefCount.cpp - Transfer functions for tracking simple values -*- 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 methods for CFRefCount, which implements -// a reference count checker for Core Foundation (Mac OS X). -// -//===----------------------------------------------------------------------===// - -#include "GRSimpleVals.h" -#include "clang/Analysis/PathSensitive/ValueState.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Analysis/LocalCheckers.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/ImmutableMap.h" -#include - -using namespace clang; - -namespace { - enum ArgEffect { IncRef, DecRef, DoNothing }; - typedef std::vector ArgEffects; -} - -namespace llvm { - template <> struct FoldingSetTrait { - static void Profile(const ArgEffects& X, FoldingSetNodeID ID) { - for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) - ID.AddInteger((unsigned) *I); - } - - static void Profile(ArgEffects& X, FoldingSetNodeID ID) { - Profile(X, ID); - } - }; -} // end llvm namespace - -namespace { - -class RetEffect { -public: - enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 }; - -private: - unsigned Data; - RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; } - -public: - - Kind getKind() const { return (Kind) (Data & 0x3); } - - unsigned getValue() const { - assert(getKind() == Alias); - return Data & ~0x3; - } - - static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); } - - static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); } - - static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); } - - operator Kind() const { return getKind(); } - - void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); } -}; - - -class CFRefSummary : public llvm::FoldingSetNode { - ArgEffects* Args; - RetEffect Ret; -public: - - CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {} - - unsigned getNumArgs() const { return Args->size(); } - - ArgEffect getArg(unsigned idx) const { - assert (idx < getNumArgs()); - return (*Args)[idx]; - } - - RetEffect getRet() const { - return Ret; - } - - typedef ArgEffects::const_iterator arg_iterator; - - arg_iterator begin_args() const { return Args->begin(); } - arg_iterator end_args() const { return Args->end(); } - - static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) { - ID.AddPointer(A); - ID.Add(R); - } - - void Profile(llvm::FoldingSetNodeID& ID) const { - Profile(ID, Args, Ret); - } -}; - - -class CFRefSummaryManager { - typedef llvm::FoldingSet > AESetTy; - typedef llvm::FoldingSet SummarySetTy; - typedef llvm::DenseMap SummaryMapTy; - - SummarySetTy SummarySet; - SummaryMapTy SummaryMap; - AESetTy AESet; - llvm::BumpPtrAllocator BPAlloc; - - ArgEffects ScratchArgs; - - - ArgEffects* getArgEffects(); - - CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain); - - CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName); - - CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT); - CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT); - - CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE); - -public: - CFRefSummaryManager() {} - ~CFRefSummaryManager(); - - CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx); -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Implementation of checker data structures. -//===----------------------------------------------------------------------===// - -CFRefSummaryManager::~CFRefSummaryManager() { - - // FIXME: The ArgEffects could eventually be allocated from BPAlloc, - // mitigating the need to do explicit cleanup of the - // Argument-Effect summaries. - - for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I) - I->getValue().~ArgEffects(); -} - -ArgEffects* CFRefSummaryManager::getArgEffects() { - - assert (!ScratchArgs.empty()); - - llvm::FoldingSetNodeID profile; - profile.Add(ScratchArgs); - void* InsertPos; - - llvm::FoldingSetNodeWrapper* E = - AESet.FindNodeOrInsertPos(profile, InsertPos); - - if (E) { - ScratchArgs.clear(); - return &E->getValue(); - } - - E = (llvm::FoldingSetNodeWrapper*) - BPAlloc.Allocate >(); - - new (E) llvm::FoldingSetNodeWrapper(ScratchArgs); - AESet.InsertNode(E, InsertPos); - - ScratchArgs.clear(); - return &E->getValue(); -} - -CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE, - RetEffect RE) { - - llvm::FoldingSetNodeID profile; - CFRefSummary::Profile(profile, AE, RE); - void* InsertPos; - - CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos); - - if (Summ) - return Summ; - - Summ = (CFRefSummary*) BPAlloc.Allocate(); - new (Summ) CFRefSummary(AE, RE); - SummarySet.InsertNode(Summ, InsertPos); - - return Summ; -} - - -CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD, - ASTContext& Ctx) { - - SourceLocation Loc = FD->getLocation(); - - if (!Loc.isFileID()) - return NULL; - - { // Look into our cache of summaries to see if we have already computed - // a summary for this FunctionDecl. - - SummaryMapTy::iterator I = SummaryMap.find(FD); - - if (I != SummaryMap.end()) - return I->second; - } - -#if 0 - SourceManager& SrcMgr = Ctx.getSourceManager(); - unsigned fid = Loc.getFileID(); - const FileEntry* FE = SrcMgr.getFileEntryForID(fid); - - if (!FE) - return NULL; - - const char* DirName = FE->getDir()->getName(); - assert (DirName); - assert (strlen(DirName) > 0); - - if (!strstr(DirName, "CoreFoundation")) { - SummaryMap[FD] = NULL; - return NULL; - } -#endif - - const char* FName = FD->getIdentifier()->getName(); - - if (FName[0] == 'C' && FName[1] == 'F') { - CFRefSummary* S = getCFSummary(FD, FName); - SummaryMap[FD] = S; - return S; - } - - return NULL; -} - -CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD, - const char* FName) { - - // For now, only generate summaries for functions that have a prototype. - - FunctionTypeProto* FT = - dyn_cast(FD->getType().getTypePtr()); - - if (!FT) - return NULL; - - FName += 2; - - if (strcmp(FName, "Retain") == 0) - return getCannedCFSummary(FT, true); - - if (strcmp(FName, "Release") == 0) - return getCannedCFSummary(FT, false); - - assert (ScratchArgs.empty()); - bool usesCreateRule = false; - - if (strstr(FName, "Create")) - usesCreateRule = true; - - if (!usesCreateRule && strstr(FName, "Copy")) - usesCreateRule = true; - - if (usesCreateRule) - return getCFSummaryCreateRule(FT); - - if (strstr(FName, "Get")) - return getCFSummaryGetRule(FT); - - return NULL; -} - -CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT, - bool isRetain) { - - if (FT->getNumArgs() != 1) - return NULL; - - TypedefType* ArgT = dyn_cast(FT->getArgType(0).getTypePtr()); - - if (!ArgT) - return NULL; - - // For CFRetain/CFRelease, the first (and only) argument is of type - // "CFTypeRef". - - const char* TDName = ArgT->getDecl()->getIdentifier()->getName(); - assert (TDName); - - if (strcmp("CFTypeRef", TDName) == 0) - return NULL; - - if (!ArgT->isPointerType()) - return NULL; - - // Check the return type. It should also be "CFTypeRef". - - QualType RetTy = FT->getResultType(); - - if (RetTy.getTypePtr() != ArgT) - return NULL; - - // The function's interface checks out. Generate a canned summary. - - assert (ScratchArgs.empty()); - ScratchArgs.push_back(isRetain ? IncRef : DecRef); - - return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0)); -} - -static bool isCFRefType(QualType T) { - - if (!T->isPointerType()) - return false; - - // Check the typedef for the name "CF" and the substring "Ref". - - TypedefType* TD = dyn_cast(T.getTypePtr()); - - if (!TD) - return false; - - const char* TDName = TD->getDecl()->getIdentifier()->getName(); - assert (TDName); - - if (TDName[0] != 'C' || TDName[1] != 'F') - return false; - - if (strstr(TDName, "Ref") == 0) - return false; - - return true; -} - - -CFRefSummary* -CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) { - - if (!isCFRefType(FT->getResultType())) - return NULL; - - assert (ScratchArgs.empty()); - - // FIXME: Add special-cases for functions that retain/release. For now - // just handle the default case. - - for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i) - ScratchArgs.push_back(DoNothing); - - return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned()); -} - -CFRefSummary* -CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) { - - if (!isCFRefType(FT->getResultType())) - return NULL; - - assert (ScratchArgs.empty()); - - // FIXME: Add special-cases for functions that retain/release. For now - // just handle the default case. - - for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i) - ScratchArgs.push_back(DoNothing); - - return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned()); -} - -//===----------------------------------------------------------------------===// -// Transfer functions. -//===----------------------------------------------------------------------===// - -namespace { - -class RefVal { - unsigned Data; - - RefVal(unsigned K, unsigned D) : Data((D << 3) | K) { - assert ((K & ~0x5) == 0x0); - } - - RefVal(unsigned K) : Data(K) { - assert ((K & ~0x5) == 0x0); - } - -public: - enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3, - ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 }; - - - Kind getKind() const { return (Kind) (Data & 0x5); } - - unsigned getCount() const { - assert (getKind() == Owned || getKind() == AcqOwned); - return Data >> 3; - } - - static bool isError(Kind k) { return k >= ErrorUseAfterRelease; } - - static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); } - static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); } - static RefVal makeNotOwned() { return RefVal(NotOwned); } - static RefVal makeReleased() { return RefVal(Released); } - static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); } - static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); } - - bool operator==(const RefVal& X) const { return Data == X.Data; } - void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); } - - void print(std::ostream& Out) const; -}; - -void RefVal::print(std::ostream& Out) const { - switch (getKind()) { - default: assert(false); - case Owned: - Out << "Owned(" << getCount() << ")"; - break; - - case AcqOwned: - Out << "Acquired-Owned(" << getCount() << ")"; - break; - - case NotOwned: - Out << "Not-Owned"; - break; - - case Released: - Out << "Released"; - break; - - case ErrorUseAfterRelease: - Out << "Use-After-Release [ERROR]"; - break; - - case ErrorReleaseNotOwned: - Out << "Release of Not-Owned [ERROR]"; - break; - } -} - -class CFRefCount : public GRSimpleVals { - - // Type definitions. - - typedef llvm::ImmutableMap RefBindings; - typedef RefBindings::Factory RefBFactoryTy; - - typedef llvm::SmallPtrSet UseAfterReleasesTy; - typedef llvm::SmallPtrSet ReleasesNotOwnedTy; - - class BindingsPrinter : public ValueState::CheckerStatePrinter { - public: - virtual void PrintCheckerState(std::ostream& Out, void* State, - const char* nl, const char* sep); - }; - - // Instance variables. - - CFRefSummaryManager Summaries; - RefBFactoryTy RefBFactory; - - UseAfterReleasesTy UseAfterReleases; - ReleasesNotOwnedTy ReleasesNotOwned; - - BindingsPrinter Printer; - - // Private methods. - - static RefBindings GetRefBindings(ValueState& StImpl) { - return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState); - } - - static void SetRefBindings(ValueState& StImpl, RefBindings B) { - StImpl.CheckerState = B.getRoot(); - } - - RefBindings Remove(RefBindings B, SymbolID sym) { - return RefBFactory.Remove(B, sym); - } - - RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E, - RefVal::Kind& hasError); - - -public: - CFRefCount() {} - virtual ~CFRefCount() {} - - virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() { - return &Printer; - } - - // Calls. - - virtual void EvalCall(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, - CallExpr* CE, LVal L, - ExplodedNode* Pred); -}; - -} // end anonymous namespace - -void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out, - void* State, const char* nl, - const char* sep) { - RefBindings B((RefBindings::TreeTy*) State); - - if (State) - Out << sep << nl; - - for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { - Out << (*I).first << " : "; - (*I).second.print(Out); - Out << nl; - } -} - -void CFRefCount::EvalCall(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, - CallExpr* CE, LVal L, - ExplodedNode* Pred) { - - ValueStateManager& StateMgr = Eng.getStateManager(); - - // FIXME: Support calls to things other than lval::FuncVal. At the very - // least we should stop tracking ref-state for ref-counted objects passed - // to these functions. - - assert (isa(L) && "Not yet implemented."); - - // Get the summary. - - lval::FuncVal FV = cast(L); - FunctionDecl* FD = FV.getDecl(); - CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext()); - - // Get the state. - - ValueState* St = Builder.GetState(Pred); - - // Evaluate the effects of the call. - - ValueState StVals = *St; - RefVal::Kind hasError = (RefVal::Kind) 0; - - if (!Summ) { - - // This function has no summary. Invalidate all reference-count state - // for arguments passed to this function, and also nuke the values of - // arguments passed-by-reference. - - ValueState StVals = *St; - - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - - RVal V = StateMgr.GetRVal(St, *I); - - if (isa(V)) { - SymbolID Sym = cast(V).getSymbol(); - RefBindings B = GetRefBindings(StVals); - SetRefBindings(StVals, Remove(B, Sym)); - } - - if (isa(V)) - StateMgr.Unbind(StVals, cast(V)); - } - - St = StateMgr.getPersistentState(StVals); - - // Make up a symbol for the return value of this function. - - if (CE->getType() != Eng.getContext().VoidTy) { - unsigned Count = Builder.getCurrentBlockCount(); - SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); - - RVal X = CE->getType()->isPointerType() - ? cast(lval::SymbolVal(Sym)) - : cast(nonlval::SymbolVal(Sym)); - - St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false); - } - - Builder.Nodify(Dst, CE, Pred, St); - return; - } - - // This function has a summary. Evaluate the effect of the arguments. - - unsigned idx = 0; - - for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); - I!=E; ++I, ++idx) { - - RVal V = StateMgr.GetRVal(St, *I); - - if (isa(V)) { - SymbolID Sym = cast(V).getSymbol(); - RefBindings B = GetRefBindings(StVals); - - if (RefBindings::TreeTy* T = B.SlimFind(Sym)) { - B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError); - SetRefBindings(StVals, B); - if (hasError) break; - } - } - } - - if (hasError) { - St = StateMgr.getPersistentState(StVals); - GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred); - - if (N) { - N->markAsSink(); - - switch (hasError) { - default: assert(false); - case RefVal::ErrorUseAfterRelease: - UseAfterReleases.insert(N); - break; - - case RefVal::ErrorReleaseNotOwned: - ReleasesNotOwned.insert(N); - break; - } - } - - return; - } - - // Finally, consult the summary for the return value. - - RetEffect RE = Summ->getRet(); - St = StateMgr.getPersistentState(StVals); - - - switch (RE.getKind()) { - default: - assert (false && "Unhandled RetEffect."); break; - - case RetEffect::Alias: { - unsigned idx = RE.getValue(); - assert (idx < CE->getNumArgs()); - RVal V = StateMgr.GetRVal(St, CE->getArg(idx)); - St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false); - break; - } - - case RetEffect::OwnedSymbol: { - unsigned Count = Builder.getCurrentBlockCount(); - SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); - - ValueState StImpl = *St; - RefBindings B = GetRefBindings(StImpl); - SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1))); - - St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), - CE, lval::SymbolVal(Sym), - Eng.getCFG().isBlkExpr(CE), false); - - break; - } - - case RetEffect::NotOwnedSymbol: { - unsigned Count = Builder.getCurrentBlockCount(); - SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); - - ValueState StImpl = *St; - RefBindings B = GetRefBindings(StImpl); - SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned())); - - St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), - CE, lval::SymbolVal(Sym), - Eng.getCFG().isBlkExpr(CE), false); - - break; - } - } - - Builder.Nodify(Dst, CE, Pred, St); -} - - -CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym, - RefVal V, ArgEffect E, - RefVal::Kind& hasError) { - - // FIXME: This dispatch can potentially be sped up by unifiying it into - // a single switch statement. Opt for simplicity for now. - - switch (E) { - default: - assert (false && "Unhandled CFRef transition."); - - case DoNothing: - if (V.getKind() == RefVal::Released) { - V = RefVal::makeUseAfterRelease(); - hasError = V.getKind(); - break; - } - - return B; - - case IncRef: - switch (V.getKind()) { - default: - assert(false); - - case RefVal::Owned: - V = RefVal::makeOwned(V.getCount()+1); break; - - case RefVal::AcqOwned: - V = RefVal::makeAcqOwned(V.getCount()+1); - break; - - case RefVal::NotOwned: - V = RefVal::makeAcqOwned(1); - break; - - case RefVal::Released: - V = RefVal::makeUseAfterRelease(); - hasError = V.getKind(); - break; - } - - case DecRef: - switch (V.getKind()) { - default: - assert (false); - - case RefVal::Owned: { - unsigned Count = V.getCount() - 1; - V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased(); - break; - } - - case RefVal::AcqOwned: { - unsigned Count = V.getCount() - 1; - V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned(); - break; - } - - case RefVal::NotOwned: - V = RefVal::makeReleaseNotOwned(); - hasError = V.getKind(); - break; - - case RefVal::Released: - V = RefVal::makeUseAfterRelease(); - hasError = V.getKind(); - break; - } - } - - return RefBFactory.Add(B, sym, V); -} - -//===----------------------------------------------------------------------===// -// Driver for the CFRefCount Checker. -//===----------------------------------------------------------------------===// - -namespace clang { - - void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx, - Diagnostic& Diag) { - - if (Diag.hasErrorOccurred()) - return; - - // FIXME: Refactor some day so this becomes a single function invocation. - - GRCoreEngine Eng(cfg, CD, Ctx); - GRExprEngine* CS = &Eng.getCheckerState(); - CFRefCount TF; - CS->setTransferFunctions(TF); - Eng.ExecuteWorkList(20000); - - } - -} // end clang namespace diff --git a/clang/Analysis/DeadStores.cpp b/clang/Analysis/DeadStores.cpp deleted file mode 100644 index 0848336e586..00000000000 --- a/clang/Analysis/DeadStores.cpp +++ /dev/null @@ -1,87 +0,0 @@ -//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a DeadStores, a flow-sensitive checker that looks for -// stores to variables that are no longer live. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/AST/ASTContext.h" -#include "llvm/Support/Compiler.h" - -using namespace clang; - -namespace { - -class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy { - ASTContext &Ctx; - Diagnostic &Diags; -public: - DeadStoreObs(ASTContext &ctx,Diagnostic &diags) : Ctx(ctx), Diags(diags){} - virtual ~DeadStoreObs() {} - - virtual void ObserveStmt(Stmt* S, - const LiveVariables::AnalysisDataTy& AD, - const LiveVariables::ValTy& Live) { - - if (BinaryOperator* B = dyn_cast(S)) { - if (!B->isAssignmentOp()) return; // Skip non-assignments. - - if (DeclRefExpr* DR = dyn_cast(B->getLHS())) - if (VarDecl* VD = dyn_cast(DR->getDecl())) - if (VD->hasLocalStorage() && !Live(VD,AD)) { - SourceRange R = B->getRHS()->getSourceRange(); - Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), - diag::warn_dead_store, 0, 0, &R, 1); - } - } - else if(DeclStmt* DS = dyn_cast(S)) - // Iterate through the decls. Warn if any initializers are complex - // expressions that are not live (never used). - for (VarDecl* V = cast(DS->getDecl()); V != NULL ; - V = cast_or_null(V->getNextDeclarator())) { - if (V->hasLocalStorage()) - if (Expr* E = V->getInit()) { - if (!Live(DS->getDecl(),AD)) { - // Special case: check for initializations with constants. - // - // e.g. : int x = 0; - // - // If x is EVER assigned a new value later, don't issue - // a warning. This is because such initialization can be - // due to defensive programming. - if (!E->isConstantExpr(Ctx,NULL)) { - // Flag a warning. - SourceRange R = E->getSourceRange(); - Diags.Report(Ctx.getFullLoc(V->getLocation()), - diag::warn_dead_store, 0, 0, &R, 1); - } - } - } - } - } -}; - -} // end anonymous namespace - -namespace clang { - -void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) { - - LiveVariables L(cfg); - L.runOnCFG(cfg); - DeadStoreObs A(Ctx, Diags); - L.runOnAllBlocks(cfg, &A); -} - -} // end namespace clang diff --git a/clang/Analysis/ExplodedGraph.cpp b/clang/Analysis/ExplodedGraph.cpp deleted file mode 100644 index 2ba46d77d63..00000000000 --- a/clang/Analysis/ExplodedGraph.cpp +++ /dev/null @@ -1,227 +0,0 @@ -//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph, -// which represent a path-sensitive, intra-procedural "exploded graph." -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include -#include - -using namespace clang; - - -static inline std::vector& getVector(void* P) { - return *reinterpret_cast*>(P); -} - -void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) { - - assert ((reinterpret_cast(N) & Mask) == 0x0); - assert (!getFlag()); - - if (getKind() == Size1) { - if (ExplodedNodeImpl* NOld = getNode()) { - std::vector* V = new std::vector(); - assert ((reinterpret_cast(V) & Mask) == 0x0); - V->push_back(NOld); - V->push_back(N); - P = reinterpret_cast(V) | SizeOther; - assert (getPtr() == (void*) V); - assert (getKind() == SizeOther); - } - else { - P = reinterpret_cast(N); - assert (getKind() == Size1); - } - } - else { - assert (getKind() == SizeOther); - getVector(getPtr()).push_back(N); - } -} - - -unsigned ExplodedNodeImpl::NodeGroup::size() const { - if (getFlag()) - return 0; - - if (getKind() == Size1) - return getNode() ? 1 : 0; - else - return getVector(getPtr()).size(); -} - -ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const { - if (getFlag()) - return NULL; - - if (getKind() == Size1) - return (ExplodedNodeImpl**) (getPtr() ? &P : NULL); - else - return const_cast(&*(getVector(getPtr()).begin())); -} - -ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const { - if (getFlag()) - return NULL; - - if (getKind() == Size1) - return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL); - else - return const_cast(&*(getVector(getPtr()).end())); -} - -ExplodedNodeImpl::NodeGroup::~NodeGroup() { - if (getKind() == SizeOther) delete &getVector(getPtr()); -} - -ExplodedGraphImpl* ExplodedGraphImpl::Trim(ExplodedNodeImpl** BeginSources, - ExplodedNodeImpl** EndSources) const{ - - typedef llvm::DenseMap Pass1Ty; - typedef llvm::DenseMap Pass2Ty; - - Pass1Ty Pass1; - Pass2Ty Pass2; - - llvm::SmallVector WL2; - - { // ===- Pass 1 (reverse BFS) -=== - - // Enqueue the source nodes to the first worklist. - - std::list > WL1; - - for (ExplodedNodeImpl** I = BeginSources; I != EndSources; ++I) - WL1.push_back(std::make_pair(*I, *I)); - - // Process the worklist. - - while (!WL1.empty()) { - - ExplodedNodeImpl* N = WL1.back().first; - ExplodedNodeImpl* Src = WL1.back().second; - - WL1.pop_back(); - - if (Pass1.find(N) != Pass1.end()) - continue; - - bool PredHasSameSource = false; - bool VisitPreds = true; - - for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); - I!=E; ++I) { - - Pass1Ty::iterator pi = Pass1.find(*I); - - if (pi == Pass1.end()) - continue; - - VisitPreds = false; - - if (pi->second == Src) { - PredHasSameSource = true; - break; - } - } - - if (VisitPreds || !PredHasSameSource) { - - Pass1[N] = Src; - - if (N->Preds.empty()) { - WL2.push_back(N); - continue; - } - } - else - Pass1[N] = NULL; - - if (VisitPreds) - for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); - I!=E; ++I) - WL1.push_front(std::make_pair(*I, Src)); - } - } - - if (WL2.empty()) - return NULL; - - ExplodedGraphImpl* G = MakeEmptyGraph(); - - // ===- Pass 2 (forward DFS to construct the new graph) -=== - - while (!WL2.empty()) { - - ExplodedNodeImpl* N = WL2.back(); - WL2.pop_back(); - - // Skip this node if we have already processed it. - - if (Pass2.find(N) != Pass2.end()) - continue; - - // Create the corresponding node in the new graph. - - ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL); - Pass2[N] = NewN; - - if (N->Preds.empty()) - G->addRoot(NewN); - - // In the case that some of the intended predecessors of NewN have already - // been created, we should hook them up as predecessors. - - for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) { - - Pass2Ty::iterator PI = Pass2.find(*I); - - if (PI == Pass2.end()) - continue; - - NewN->addPredecessor(PI->second); - } - - // In the case that some of the intended successors of NewN have already - // been created, we should hook them up as successors. Otherwise, enqueue - // the new nodes from the original graph that should have nodes created - // in the new graph. - - for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) { - - Pass2Ty::iterator PI = Pass2.find(*I); - - if (PI != Pass2.end()) { - PI->second->addPredecessor(NewN); - continue; - } - - // Enqueue nodes to the worklist that were marked during pass 1. - - Pass1Ty::iterator pi = Pass1.find(*I); - - if (pi == Pass1.end() || pi->second == NULL) - continue; - - WL2.push_back(*I); - } - - if (N->isSink()) - NewN->markAsSink(); - } - - return G; -} diff --git a/clang/Analysis/GRBlockCounter.cpp b/clang/Analysis/GRBlockCounter.cpp deleted file mode 100644 index 3ecc39d3224..00000000000 --- a/clang/Analysis/GRBlockCounter.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count -// the number of times a given block has been visited along a path -// analyzed by GRCoreEngine. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/GRBlockCounter.h" -#include "llvm/ADT/ImmutableMap.h" - -using namespace clang; - -typedef llvm::ImmutableMap CountMap; - -static inline CountMap GetMap(void* D) { - return CountMap(static_cast(D)); -} - -static inline CountMap::Factory& GetFactory(void* F) { - return *static_cast(F); -} - -unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const { - CountMap M = GetMap(Data); - CountMap::TreeTy* T = M.SlimFind(BlockID); - return T ? T->getValue().second : 0; -} - -GRBlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) { - F = new CountMap::Factory(Alloc); -} - -GRBlockCounter::Factory::~Factory() { - delete static_cast(F); -} - -GRBlockCounter -GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) { - return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID, - BC.getNumVisited(BlockID)+1).getRoot()); -} - -GRBlockCounter -GRBlockCounter::Factory::GetEmptyCounter() { - return GRBlockCounter(GetFactory(F).GetEmptyMap().getRoot()); -} diff --git a/clang/Analysis/GRCoreEngine.cpp b/clang/Analysis/GRCoreEngine.cpp deleted file mode 100644 index 53831ed06d5..00000000000 --- a/clang/Analysis/GRCoreEngine.cpp +++ /dev/null @@ -1,444 +0,0 @@ -//==- GRCoreEngine.cpp - Path-Sensitive Dataflow 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 a generic engine for intraprocedural, path-sensitive, -// dataflow analysis via graph reachability engine. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/GRCoreEngine.h" -#include "clang/AST/Expr.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Casting.h" -#include "llvm/ADT/DenseMap.h" -#include - -using llvm::cast; -using llvm::isa; -using namespace clang; - -namespace { - class VISIBILITY_HIDDEN DFS : public GRWorkList { - llvm::SmallVector Stack; -public: - virtual bool hasWork() const { - return !Stack.empty(); - } - - virtual void Enqueue(const GRWorkListUnit& U) { - Stack.push_back(U); - } - - virtual GRWorkListUnit Dequeue() { - assert (!Stack.empty()); - const GRWorkListUnit& U = Stack.back(); - Stack.pop_back(); // This technically "invalidates" U, but we are fine. - return U; - } -}; -} // end anonymous namespace - -// Place the dstor for GRWorkList here because it contains virtual member -// functions, and we the code for the dstor generated in one compilation unit. -GRWorkList::~GRWorkList() {} - -GRWorkList* GRWorkList::MakeDFS() { return new DFS(); } - -/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. -bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { - - if (G->num_roots() == 0) { // Initialize the analysis by constructing - // the root if none exists. - - CFGBlock* Entry = &getCFG().getEntry(); - - assert (Entry->empty() && - "Entry block must be empty."); - - assert (Entry->succ_size() == 1 && - "Entry block must have 1 successor."); - - // Get the solitary successor. - CFGBlock* Succ = *(Entry->succ_begin()); - - // Construct an edge representing the - // starting location in the function. - BlockEdge StartLoc(getCFG(), Entry, Succ); - - // Set the current block counter to being empty. - WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); - - // Generate the root. - GenerateNode(StartLoc, getInitialState()); - } - - while (Steps && WList->hasWork()) { - --Steps; - const GRWorkListUnit& WU = WList->Dequeue(); - - // Set the current block counter. - WList->setBlockCounter(WU.getBlockCounter()); - - // Retrieve the node. - ExplodedNodeImpl* Node = WU.getNode(); - - // Dispatch on the location type. - switch (Node->getLocation().getKind()) { - default: - assert (isa(Node->getLocation())); - HandleBlockEdge(cast(Node->getLocation()), Node); - break; - - case ProgramPoint::BlockEntranceKind: - HandleBlockEntrance(cast(Node->getLocation()), Node); - break; - - case ProgramPoint::BlockExitKind: - assert (false && "BlockExit location never occur in forward analysis."); - break; - - case ProgramPoint::PostStmtKind: - HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), - WU.getIndex(), Node); - break; - } - } - - return WList->hasWork(); -} - -void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L, - ExplodedNodeImpl* Pred) { - - CFGBlock* Blk = L.getDst(); - - // Check if we are entering the EXIT block. - if (Blk == &getCFG().getExit()) { - - assert (getCFG().getExit().size() == 0 - && "EXIT block cannot contain Stmts."); - - // Process the final state transition. - void* State = ProcessEOP(Blk, Pred->State); - - bool IsNew; - ExplodedNodeImpl* Node = G->getNodeImpl(BlockEntrance(Blk), State, &IsNew); - Node->addPredecessor(Pred); - - // If the node was freshly created, mark it as an "End-Of-Path" node. - if (IsNew) G->addEndOfPath(Node); - - // This path is done. Don't enqueue any more nodes. - return; - } - - // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? - - if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter())) - GenerateNode(BlockEntrance(Blk), Pred->State, Pred); -} - -void GRCoreEngineImpl::HandleBlockEntrance(const BlockEntrance& L, - ExplodedNodeImpl* Pred) { - - // Increment the block counter. - GRBlockCounter Counter = WList->getBlockCounter(); - Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID()); - WList->setBlockCounter(Counter); - - // Process the entrance of the block. - if (Stmt* S = L.getFirstStmt()) { - GRStmtNodeBuilderImpl Builder(L.getBlock(), 0, Pred, this); - ProcessStmt(S, Builder); - } - else - HandleBlockExit(L.getBlock(), Pred); -} - - -void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) { - - if (Stmt* Term = B->getTerminator()) { - switch (Term->getStmtClass()) { - default: - assert(false && "Analysis for this terminator not implemented."); - break; - - case Stmt::BinaryOperatorClass: // '&&' and '||' - HandleBranch(cast(Term)->getLHS(), Term, B, Pred); - return; - - case Stmt::ConditionalOperatorClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - // FIXME: Use constant-folding in CFG construction to simplify this - // case. - - case Stmt::ChooseExprClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::DoStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::ForStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::ContinueStmtClass: - case Stmt::BreakStmtClass: - case Stmt::GotoStmtClass: - break; - - case Stmt::IfStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - - case Stmt::IndirectGotoStmtClass: { - // Only 1 successor: the indirect goto dispatch block. - assert (B->succ_size() == 1); - - GRIndirectGotoNodeBuilderImpl - builder(Pred, B, cast(Term)->getTarget(), - *(B->succ_begin()), this); - - ProcessIndirectGoto(builder); - return; - } - - case Stmt::SwitchStmtClass: { - GRSwitchNodeBuilderImpl builder(Pred, B, - cast(Term)->getCond(), - this); - - ProcessSwitch(builder); - return; - } - - case Stmt::WhileStmtClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); - return; - } - } - - assert (B->succ_size() == 1 && - "Blocks with no terminator should have at most 1 successor."); - - GenerateNode(BlockEdge(getCFG(),B,*(B->succ_begin())), Pred->State, Pred); -} - -void GRCoreEngineImpl::HandleBranch(Expr* Cond, Stmt* Term, CFGBlock * B, - ExplodedNodeImpl* Pred) { - assert (B->succ_size() == 2); - - GRBranchNodeBuilderImpl Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), - Pred, this); - - ProcessBranch(Cond, Term, Builder); -} - -void GRCoreEngineImpl::HandlePostStmt(const PostStmt& L, CFGBlock* B, - unsigned StmtIdx, ExplodedNodeImpl* Pred) { - - assert (!B->empty()); - - if (StmtIdx == B->size()) - HandleBlockExit(B, Pred); - else { - GRStmtNodeBuilderImpl Builder(B, StmtIdx, Pred, this); - ProcessStmt((*B)[StmtIdx], Builder); - } -} - -typedef llvm::DenseMap ParentMapTy; -/// PopulateParentMap - Recurse the AST starting at 'Parent' and add the -/// mappings between child and parent to ParentMap. -static void PopulateParentMap(Stmt* Parent, ParentMapTy& M) { - for (Stmt::child_iterator I=Parent->child_begin(), - E=Parent->child_end(); I!=E; ++I) { - - assert (M.find(*I) == M.end()); - M[*I] = Parent; - PopulateParentMap(*I, M); - } -} - -/// GenerateNode - Utility method to generate nodes, hook up successors, -/// and add nodes to the worklist. -void GRCoreEngineImpl::GenerateNode(const ProgramPoint& Loc, void* State, - ExplodedNodeImpl* Pred) { - - bool IsNew; - ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew); - - if (Pred) - Node->addPredecessor(Pred); // Link 'Node' with its predecessor. - else { - assert (IsNew); - G->addRoot(Node); // 'Node' has no predecessor. Make it a root. - } - - // Only add 'Node' to the worklist if it was freshly generated. - if (IsNew) WList->Enqueue(Node); -} - -GRStmtNodeBuilderImpl::GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, - ExplodedNodeImpl* N, GRCoreEngineImpl* e) - : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Populated(false) { - Deferred.insert(N); -} - -GRStmtNodeBuilderImpl::~GRStmtNodeBuilderImpl() { - for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) - if (!(*I)->isSink()) - GenerateAutoTransition(*I); -} - -void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) { - assert (!N->isSink()); - - PostStmt Loc(getStmt()); - - if (Loc == N->getLocation()) { - // Note: 'N' should be a fresh node because otherwise it shouldn't be - // a member of Deferred. - Eng.WList->Enqueue(N, B, Idx+1); - return; - } - - bool IsNew; - ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(Loc, N->State, &IsNew); - Succ->addPredecessor(N); - - if (IsNew) - Eng.WList->Enqueue(Succ, B, Idx+1); -} - -ExplodedNodeImpl* GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State, - ExplodedNodeImpl* Pred) { - - bool IsNew; - ExplodedNodeImpl* N = Eng.G->getNodeImpl(PostStmt(S), State, &IsNew); - N->addPredecessor(Pred); - Deferred.erase(Pred); - - HasGeneratedNode = true; - - if (IsNew) { - Deferred.insert(N); - LastNode = N; - return N; - } - - LastNode = NULL; - return NULL; -} - -ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(void* State, - bool branch) { - bool IsNew; - - ExplodedNodeImpl* Succ = - Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, branch ? DstT : DstF), - State, &IsNew); - - Succ->addPredecessor(Pred); - - if (branch) GeneratedTrue = true; - else GeneratedFalse = true; - - if (IsNew) { - Deferred.push_back(Succ); - return Succ; - } - - return NULL; -} - -GRBranchNodeBuilderImpl::~GRBranchNodeBuilderImpl() { - if (!GeneratedTrue) generateNodeImpl(Pred->State, true); - if (!GeneratedFalse) generateNodeImpl(Pred->State, false); - - for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) - if (!(*I)->isSink()) Eng.WList->Enqueue(*I); -} - - -ExplodedNodeImpl* -GRIndirectGotoNodeBuilderImpl::generateNodeImpl(const Iterator& I, - void* St, - bool isSink) { - bool IsNew; - - ExplodedNodeImpl* Succ = - Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, I.getBlock(), true), - St, &IsNew); - - Succ->addPredecessor(Pred); - - if (IsNew) { - - if (isSink) - Succ->markAsSink(); - else - Eng.WList->Enqueue(Succ); - - return Succ; - } - - return NULL; -} - - -ExplodedNodeImpl* -GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I, void* St) { - - bool IsNew; - - ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, - I.getBlock()), - St, &IsNew); - Succ->addPredecessor(Pred); - - if (IsNew) { - Eng.WList->Enqueue(Succ); - return Succ; - } - - return NULL; -} - - -ExplodedNodeImpl* -GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(void* St, bool isSink) { - - // Get the block for the default case. - assert (Src->succ_rbegin() != Src->succ_rend()); - CFGBlock* DefaultBlock = *Src->succ_rbegin(); - - bool IsNew; - - ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, - DefaultBlock), - St, &IsNew); - Succ->addPredecessor(Pred); - - if (IsNew) { - if (isSink) - Succ->markAsSink(); - else - Eng.WList->Enqueue(Succ); - - return Succ; - } - - return NULL; -} diff --git a/clang/Analysis/GRExprEngine.cpp b/clang/Analysis/GRExprEngine.cpp deleted file mode 100644 index f1108df4051..00000000000 --- a/clang/Analysis/GRExprEngine.cpp +++ /dev/null @@ -1,1941 +0,0 @@ -//=-- GRExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-= -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines a meta-engine for path-sensitive dataflow analysis that -// is built on GREngine, but provides the boilerplate to execute transfer -// functions and build the ExplodedGraph at the expression level. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/Streams.h" - -#ifndef NDEBUG -#include "llvm/Support/GraphWriter.h" -#include -#endif - -// SaveAndRestore - A utility class that uses RIIA to save and restore -// the value of a variable. -template -struct VISIBILITY_HIDDEN SaveAndRestore { - SaveAndRestore(T& x) : X(x), old_value(x) {} - ~SaveAndRestore() { X = old_value; } - T get() { return old_value; } - - T& X; - T old_value; -}; - -using namespace clang; -using llvm::dyn_cast; -using llvm::cast; -using llvm::APSInt; - - -ValueState* GRExprEngine::getInitialState() { - - // The LiveVariables information already has a compilation of all VarDecls - // used in the function. Iterate through this set, and "symbolicate" - // any VarDecl whose value originally comes from outside the function. - - typedef LiveVariables::AnalysisDataTy LVDataTy; - LVDataTy& D = Liveness.getAnalysisData(); - - ValueState StateImpl = *StateMgr.getInitialState(); - - for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) { - - VarDecl* VD = cast(const_cast(I->first)); - - if (VD->hasGlobalStorage() || isa(VD)) { - RVal X = RVal::GetSymbolValue(SymMgr, VD); - StateMgr.BindVar(StateImpl, VD, X); - } - } - - return StateMgr.getPersistentState(StateImpl); -} - -ValueState* GRExprEngine::SetRVal(ValueState* St, Expr* Ex, RVal V) { - - bool isBlkExpr = false; - - if (Ex == CurrentStmt) { - isBlkExpr = getCFG().isBlkExpr(Ex); - - if (!isBlkExpr) - return St; - } - - return StateMgr.SetRVal(St, Ex, V, isBlkExpr, false); -} - -ValueState* GRExprEngine::MarkBranch(ValueState* St, Stmt* Terminator, - bool branchTaken) { - - switch (Terminator->getStmtClass()) { - default: - return St; - - case Stmt::BinaryOperatorClass: { // '&&' and '||' - - BinaryOperator* B = cast(Terminator); - BinaryOperator::Opcode Op = B->getOpcode(); - - assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr); - - // For &&, if we take the true branch, then the value of the whole - // expression is that of the RHS expression. - // - // For ||, if we take the false branch, then the value of the whole - // expression is that of the RHS expression. - - Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) || - (Op == BinaryOperator::LOr && !branchTaken) - ? B->getRHS() : B->getLHS(); - - return SetBlkExprRVal(St, B, UndefinedVal(Ex)); - } - - case Stmt::ConditionalOperatorClass: { // ?: - - ConditionalOperator* C = cast(Terminator); - - // For ?, if branchTaken == true then the value is either the LHS or - // the condition itself. (GNU extension). - - Expr* Ex; - - if (branchTaken) - Ex = C->getLHS() ? C->getLHS() : C->getCond(); - else - Ex = C->getRHS(); - - return SetBlkExprRVal(St, C, UndefinedVal(Ex)); - } - - case Stmt::ChooseExprClass: { // ?: - - ChooseExpr* C = cast(Terminator); - - Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); - return SetBlkExprRVal(St, C, UndefinedVal(Ex)); - } - } -} - -bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, ValueState*, - GRBlockCounter BC) { - - return BC.getNumVisited(B->getBlockID()) < 3; -} - -void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term, - BranchNodeBuilder& builder) { - - // Remove old bindings for subexpressions. - ValueState* PrevState = StateMgr.RemoveSubExprBindings(builder.getState()); - - // Check for NULL conditions; e.g. "for(;;)" - if (!Condition) { - builder.markInfeasible(false); - return; - } - - RVal V = GetRVal(PrevState, Condition); - - switch (V.getBaseKind()) { - default: - break; - - case RVal::UnknownKind: - builder.generateNode(MarkBranch(PrevState, Term, true), true); - builder.generateNode(MarkBranch(PrevState, Term, false), false); - return; - - case RVal::UndefinedKind: { - NodeTy* N = builder.generateNode(PrevState, true); - - if (N) { - N->markAsSink(); - UndefBranches.insert(N); - } - - builder.markInfeasible(false); - return; - } - } - - - // Process the true branch. - - bool isFeasible = false; - ValueState* St = Assume(PrevState, V, true, isFeasible); - - if (isFeasible) - builder.generateNode(MarkBranch(St, Term, true), true); - else - builder.markInfeasible(true); - - // Process the false branch. - - isFeasible = false; - St = Assume(PrevState, V, false, isFeasible); - - if (isFeasible) - builder.generateNode(MarkBranch(St, Term, false), false); - else - builder.markInfeasible(false); -} - -/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor -/// nodes by processing the 'effects' of a computed goto jump. -void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) { - - ValueState* St = builder.getState(); - RVal V = GetRVal(St, builder.getTarget()); - - // Three possibilities: - // - // (1) We know the computed label. - // (2) The label is NULL (or some other constant), or Undefined. - // (3) We have no clue about the label. Dispatch to all targets. - // - - typedef IndirectGotoNodeBuilder::iterator iterator; - - if (isa(V)) { - LabelStmt* L = cast(V).getLabel(); - - for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) { - if (I.getLabel() == L) { - builder.generateNode(I, St); - return; - } - } - - assert (false && "No block with label."); - return; - } - - if (isa(V) || isa(V)) { - // Dispatch to the first target and mark it as a sink. - NodeTy* N = builder.generateNode(builder.begin(), St, true); - UndefBranches.insert(N); - return; - } - - // This is really a catch-all. We don't support symbolics yet. - - assert (V.isUnknown()); - - for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) - builder.generateNode(I, St); -} - -/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor -/// nodes by processing the 'effects' of a switch statement. -void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { - - typedef SwitchNodeBuilder::iterator iterator; - - ValueState* St = builder.getState(); - Expr* CondE = builder.getCondition(); - RVal CondV = GetRVal(St, CondE); - - if (CondV.isUndef()) { - NodeTy* N = builder.generateDefaultCaseNode(St, true); - UndefBranches.insert(N); - return; - } - - ValueState* DefaultSt = St; - - // While most of this can be assumed (such as the signedness), having it - // just computed makes sure everything makes the same assumptions end-to-end. - - unsigned bits = getContext().getTypeSize(CondE->getType()); - - APSInt V1(bits, false); - APSInt V2 = V1; - - for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) { - - CaseStmt* Case = cast(I.getCase()); - - // Evaluate the case. - if (!Case->getLHS()->isIntegerConstantExpr(V1, getContext(), 0, true)) { - assert (false && "Case condition must evaluate to an integer constant."); - return; - } - - // Get the RHS of the case, if it exists. - - if (Expr* E = Case->getRHS()) { - if (!E->isIntegerConstantExpr(V2, getContext(), 0, true)) { - assert (false && - "Case condition (RHS) must evaluate to an integer constant."); - return ; - } - - assert (V1 <= V2); - } - else V2 = V1; - - // FIXME: Eventually we should replace the logic below with a range - // comparison, rather than concretize the values within the range. - // This should be easy once we have "ranges" for NonLVals. - - do { - nonlval::ConcreteInt CaseVal(BasicVals.getValue(V1)); - - RVal Res = EvalBinOp(BinaryOperator::EQ, CondV, CaseVal); - - // Now "assume" that the case matches. - - bool isFeasible = false; - ValueState* StNew = Assume(St, Res, true, isFeasible); - - if (isFeasible) { - builder.generateCaseStmtNode(I, StNew); - - // If CondV evaluates to a constant, then we know that this - // is the *only* case that we can take, so stop evaluating the - // others. - if (isa(CondV)) - return; - } - - // Now "assume" that the case doesn't match. Add this state - // to the default state (if it is feasible). - - isFeasible = false; - StNew = Assume(DefaultSt, Res, false, isFeasible); - - if (isFeasible) - DefaultSt = StNew; - - // Concretize the next value in the range. - ++V1; - - } while (V1 < V2); - } - - // If we reach here, than we know that the default branch is - // possible. - builder.generateDefaultCaseNode(DefaultSt); -} - - -void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, - NodeSet& Dst) { - - assert (B->getOpcode() == BinaryOperator::LAnd || - B->getOpcode() == BinaryOperator::LOr); - - assert (B == CurrentStmt && getCFG().isBlkExpr(B)); - - ValueState* St = GetState(Pred); - RVal X = GetBlkExprRVal(St, B); - - assert (X.isUndef()); - - Expr* Ex = (Expr*) cast(X).getData(); - - assert (Ex); - - if (Ex == B->getRHS()) { - - X = GetBlkExprRVal(St, Ex); - - // Handle undefined values. - - if (X.isUndef()) { - Nodify(Dst, B, Pred, SetBlkExprRVal(St, B, X)); - return; - } - - // We took the RHS. Because the value of the '&&' or '||' expression must - // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 - // or 1. Alternatively, we could take a lazy approach, and calculate this - // value later when necessary. We don't have the machinery in place for - // this right now, and since most logical expressions are used for branches, - // the payoff is not likely to be large. Instead, we do eager evaluation. - - bool isFeasible = false; - ValueState* NewState = Assume(St, X, true, isFeasible); - - if (isFeasible) - Nodify(Dst, B, Pred, SetBlkExprRVal(NewState, B, MakeConstantVal(1U, B))); - - isFeasible = false; - NewState = Assume(St, X, false, isFeasible); - - if (isFeasible) - Nodify(Dst, B, Pred, SetBlkExprRVal(NewState, B, MakeConstantVal(0U, B))); - } - else { - // We took the LHS expression. Depending on whether we are '&&' or - // '||' we know what the value of the expression is via properties of - // the short-circuiting. - - X = MakeConstantVal( B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, B); - Nodify(Dst, B, Pred, SetBlkExprRVal(St, B, X)); - } -} - - -void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { - - Builder = &builder; - StmtEntryNode = builder.getLastNode(); - CurrentStmt = S; - NodeSet Dst; - - // Create the cleaned state. - - CleanedState = StateMgr.RemoveDeadBindings(StmtEntryNode->getState(), - CurrentStmt, Liveness); - - Builder->SetCleanedState(CleanedState); - - // Visit the statement. - - Visit(S, StmtEntryNode, Dst); - - // If no nodes were generated, generate a new node that has all the - // dead mappings removed. - - if (Dst.size() == 1 && *Dst.begin() == StmtEntryNode) - builder.generateNode(S, GetState(StmtEntryNode), StmtEntryNode); - - // NULL out these variables to cleanup. - - CurrentStmt = NULL; - StmtEntryNode = NULL; - Builder = NULL; - CleanedState = NULL; -} - -void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ - - if (D != CurrentStmt) { - Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. - return; - } - - // If we are here, we are loading the value of the decl and binding - // it to the block-level expression. - - ValueState* St = GetState(Pred); - RVal X = RVal::MakeVal(BasicVals, D); - RVal Y = isa(X) ? GetRVal(St, cast(X)) : X; - Nodify(Dst, D, Pred, SetBlkExprRVal(St, D, Y)); -} - -void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred, - CallExpr::arg_iterator AI, - CallExpr::arg_iterator AE, - NodeSet& Dst) { - - // Process the arguments. - - if (AI != AE) { - - NodeSet DstTmp; - Visit(*AI, Pred, DstTmp); - ++AI; - - for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI) - VisitCall(CE, *DI, AI, AE, Dst); - - return; - } - - // If we reach here we have processed all of the arguments. Evaluate - // the callee expression. - - NodeSet DstTmp; - Expr* Callee = CE->getCallee()->IgnoreParenCasts(); - - VisitLVal(Callee, Pred, DstTmp); - - if (DstTmp.empty()) - DstTmp.Add(Pred); - - // Finally, evaluate the function call. - for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { - - ValueState* St = GetState(*DI); - RVal L = GetLVal(St, Callee); - - // FIXME: Add support for symbolic function calls (calls involving - // function pointer values that are symbolic). - - // Check for undefined control-flow or calls to NULL. - - if (L.isUndef() || isa(L)) { - NodeTy* N = Builder->generateNode(CE, St, *DI); - - if (N) { - N->markAsSink(); - BadCalls.insert(N); - } - - continue; - } - - // Check for the "noreturn" attribute. - - SaveAndRestore OldSink(Builder->BuildSinks); - - if (isa(L)) { - - FunctionDecl* FD = cast(L).getDecl(); - - if (FD->getAttr()) - Builder->BuildSinks = true; - else { - // HACK: Some functions are not marked noreturn, and don't return. - // Here are a few hardwired ones. If this takes too long, we can - // potentially cache these results. - const char* s = FD->getIdentifier()->getName(); - unsigned n = strlen(s); - - switch (n) { - default: - break; - - case 4: - if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true; - break; - - case 5: - if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true; - break; - } - } - } - - // Evaluate the call. - - - bool invalidateArgs = false; - - if (L.isUnknown()) { - // Check for an "unknown" callee. - invalidateArgs = true; - } - else if (isa(L)) { - - IdentifierInfo* Info = cast(L).getDecl()->getIdentifier(); - - if (unsigned id = Info->getBuiltinID()) { - switch (id) { - case Builtin::BI__builtin_expect: { - // For __builtin_expect, just return the value of the subexpression. - assert (CE->arg_begin() != CE->arg_end()); - RVal X = GetRVal(St, *(CE->arg_begin())); - Nodify(Dst, CE, *DI, SetRVal(St, CE, X)); - continue; - } - - default: - invalidateArgs = true; - break; - } - } - } - - if (invalidateArgs) { - // Invalidate all arguments passed in by reference (LVals). - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - RVal V = GetRVal(St, *I); - - if (isa(V)) - St = SetRVal(St, cast(V), UnknownVal()); - } - - Nodify(Dst, CE, *DI, St); - } - else { - - // Check any arguments passed-by-value against being undefined. - - bool badArg = false; - - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - - if (GetRVal(GetState(*DI), *I).isUndef()) { - NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI); - - if (N) { - N->markAsSink(); - UndefArgs[N] = *I; - } - - badArg = true; - break; - } - } - - if (badArg) - continue; - - // Dispatch to the plug-in transfer function. - - unsigned size = Dst.size(); - - EvalCall(Dst, CE, cast(L), *DI); - - if (!Builder->BuildSinks && Dst.size() == size) - Nodify(Dst, CE, *DI, St); - } - } -} - -void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ - - NodeSet S1; - QualType T = CastE->getType(); - - if (T->isReferenceType()) - VisitLVal(Ex, Pred, S1); - else - Visit(Ex, Pred, S1); - - // Check for redundant casts or casting to "void" - if (T->isVoidType() || - Ex->getType() == T || - (T->isPointerType() && Ex->getType()->isFunctionType())) { - - for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) - Dst.Add(*I1); - - return; - } - - for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { - NodeTy* N = *I1; - ValueState* St = GetState(N); - - RVal V = T->isReferenceType() ? GetLVal(St, Ex) : GetRVal(St, Ex); - - Nodify(Dst, CastE, N, SetRVal(St, CastE, EvalCast(V, CastE->getType()))); - } -} - -void GRExprEngine::VisitDeclStmt(DeclStmt* DS, GRExprEngine::NodeTy* Pred, - GRExprEngine::NodeSet& Dst) { - - ValueState* St = GetState(Pred); - - for (const ScopedDecl* D = DS->getDecl(); D; D = D->getNextDeclarator()) - if (const VarDecl* VD = dyn_cast(D)) { - - // FIXME: Add support for local arrays. - if (VD->getType()->isArrayType()) - continue; - - const Expr* Ex = VD->getInit(); - - if (!VD->hasGlobalStorage() || VD->getStorageClass() == VarDecl::Static) { - - // In this context, Static => Local variable. - - assert (!VD->getStorageClass() == VarDecl::Static || - !isa(VD)); - - // If there is no initializer, set the value of the - // variable to "Undefined". - // - // FIXME: static variables may have an initializer, but the second - // time a function is called those values may not be current. - - QualType T = VD->getType(); - - if ( VD->getStorageClass() == VarDecl::Static) { - - // C99: 6.7.8 Initialization - // If an object that has static storage duration is not initialized - // explicitly, then: - // —if it has pointer type, it is initialized to a null pointer; - // —if it has arithmetic type, it is initialized to (positive or - // unsigned) zero; - - // FIXME: Handle structs. Now we treat their values as unknown. - - if (T->isPointerType()) { - - St = SetRVal(St, lval::DeclVal(VD), - lval::ConcreteInt(BasicVals.getValue(0, T))); - } - else if (T->isIntegerType()) { - - St = SetRVal(St, lval::DeclVal(VD), - nonlval::ConcreteInt(BasicVals.getValue(0, T))); - } - - - } - else { - - // FIXME: Handle structs. Now we treat them as unknown. What - // we need to do is treat their members as unknown. - - if (T->isPointerType() || T->isIntegerType()) - St = SetRVal(St, lval::DeclVal(VD), - Ex ? GetRVal(St, Ex) : UndefinedVal()); - } - } - } - - Nodify(Dst, DS, Pred, St); -} - - -void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, - NodeTy* Pred, NodeSet& Dst) { - - assert (Ex == CurrentStmt && getCFG().isBlkExpr(Ex)); - - ValueState* St = GetState(Pred); - RVal X = GetBlkExprRVal(St, Ex); - - assert (X.isUndef()); - - Expr* SE = (Expr*) cast(X).getData(); - - assert (SE); - - X = GetBlkExprRVal(St, SE); - - // Make sure that we invalidate the previous binding. - Nodify(Dst, Ex, Pred, StateMgr.SetRVal(St, Ex, X, true, true)); -} - -/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type). -void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, - NodeTy* Pred, - NodeSet& Dst) { - - QualType T = Ex->getArgumentType(); - uint64_t amt; - - if (Ex->isSizeOf()) { - - // FIXME: Add support for VLAs. - if (!T.getTypePtr()->isConstantSizeType()) - return; - - amt = 1; // Handle sizeof(void) - - if (T != getContext().VoidTy) - amt = getContext().getTypeSize(T) / 8; - - } - else // Get alignment of the type. - amt = getContext().getTypeAlign(T) / 8; - - Nodify(Dst, Ex, Pred, - SetRVal(GetState(Pred), Ex, - NonLVal::MakeVal(BasicVals, amt, Ex->getType()))); -} - -void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, - NodeSet& Dst, bool GetLVal) { - - Expr* Ex = U->getSubExpr()->IgnoreParens(); - - NodeSet DstTmp; - - if (isa(Ex)) - DstTmp.Add(Pred); - else - Visit(Ex, Pred, DstTmp); - - for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) { - - NodeTy* N = *I; - ValueState* St = GetState(N); - - // FIXME: Bifurcate when dereferencing a symbolic with no constraints? - - RVal V = GetRVal(St, Ex); - - // Check for dereferences of undefined values. - - if (V.isUndef()) { - - NodeTy* Succ = Builder->generateNode(U, St, N); - - if (Succ) { - Succ->markAsSink(); - UndefDeref.insert(Succ); - } - - continue; - } - - // Check for dereferences of unknown values. Treat as No-Ops. - - if (V.isUnknown()) { - Dst.Add(N); - continue; - } - - // After a dereference, one of two possible situations arise: - // (1) A crash, because the pointer was NULL. - // (2) The pointer is not NULL, and the dereference works. - // - // We add these assumptions. - - LVal LV = cast(V); - bool isFeasibleNotNull; - - // "Assume" that the pointer is Not-NULL. - - ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull); - - if (isFeasibleNotNull) { - - if (GetLVal) Nodify(Dst, U, N, SetRVal(StNotNull, U, LV)); - else { - - // FIXME: Currently symbolic analysis "generates" new symbols - // for the contents of values. We need a better approach. - - Nodify(Dst, U, N, SetRVal(StNotNull, U, - GetRVal(StNotNull, LV, U->getType()))); - } - } - - bool isFeasibleNull; - - // Now "assume" that the pointer is NULL. - - ValueState* StNull = Assume(St, LV, false, isFeasibleNull); - - if (isFeasibleNull) { - - // We don't use "Nodify" here because the node will be a sink - // and we have no intention of processing it later. - - NodeTy* NullNode = Builder->generateNode(U, StNull, N); - - if (NullNode) { - - NullNode->markAsSink(); - - if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode); - else ExplicitNullDeref.insert(NullNode); - } - } - } -} - -void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, - NodeSet& Dst) { - - NodeSet S1; - - assert (U->getOpcode() != UnaryOperator::Deref); - assert (U->getOpcode() != UnaryOperator::SizeOf); - assert (U->getOpcode() != UnaryOperator::AlignOf); - - bool use_GetLVal = false; - - switch (U->getOpcode()) { - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - case UnaryOperator::AddrOf: - // Evalue subexpression as an LVal. - use_GetLVal = true; - VisitLVal(U->getSubExpr(), Pred, S1); - break; - - default: - Visit(U->getSubExpr(), Pred, S1); - break; - } - - for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { - - NodeTy* N1 = *I1; - ValueState* St = GetState(N1); - - RVal SubV = use_GetLVal ? GetLVal(St, U->getSubExpr()) : - GetRVal(St, U->getSubExpr()); - - if (SubV.isUnknown()) { - Dst.Add(N1); - continue; - } - - if (SubV.isUndef()) { - Nodify(Dst, U, N1, SetRVal(St, U, SubV)); - continue; - } - - if (U->isIncrementDecrementOp()) { - - // Handle ++ and -- (both pre- and post-increment). - - LVal SubLV = cast(SubV); - RVal V = GetRVal(St, SubLV, U->getType()); - - if (V.isUnknown()) { - Dst.Add(N1); - continue; - } - - // Propagate undefined values. - if (V.isUndef()) { - Nodify(Dst, U, N1, SetRVal(St, U, V)); - continue; - } - - // Handle all other values. - - BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add - : BinaryOperator::Sub; - - RVal Result = EvalBinOp(Op, V, MakeConstantVal(1U, U)); - - if (U->isPostfix()) - St = SetRVal(SetRVal(St, U, V), SubLV, Result); - else - St = SetRVal(SetRVal(St, U, Result), SubLV, Result); - - Nodify(Dst, U, N1, St); - continue; - } - - // Handle all other unary operators. - - switch (U->getOpcode()) { - - case UnaryOperator::Extension: - St = SetRVal(St, U, SubV); - break; - - case UnaryOperator::Minus: - St = SetRVal(St, U, EvalMinus(U, cast(SubV))); - break; - - case UnaryOperator::Not: - St = SetRVal(St, U, EvalComplement(cast(SubV))); - break; - - case UnaryOperator::LNot: - - // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." - // - // Note: technically we do "E == 0", but this is the same in the - // transfer functions as "0 == E". - - if (isa(SubV)) { - lval::ConcreteInt V(BasicVals.getZeroWithPtrWidth()); - RVal Result = EvalBinOp(BinaryOperator::EQ, cast(SubV), V); - St = SetRVal(St, U, Result); - } - else { - Expr* Ex = U->getSubExpr(); - nonlval::ConcreteInt V(BasicVals.getValue(0, Ex->getType())); - RVal Result = EvalBinOp(BinaryOperator::EQ, cast(SubV), V); - St = SetRVal(St, U, Result); - } - - break; - - case UnaryOperator::AddrOf: { - assert (isa(SubV)); - St = SetRVal(St, U, SubV); - break; - } - - default: ; - assert (false && "Not implemented."); - } - - Nodify(Dst, U, N1, St); - } -} - -void GRExprEngine::VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, - NodeSet& Dst) { - - QualType T = U->getSubExpr()->getType(); - - // FIXME: Add support for VLAs. - if (!T.getTypePtr()->isConstantSizeType()) - return; - - uint64_t size = getContext().getTypeSize(T) / 8; - ValueState* St = GetState(Pred); - St = SetRVal(St, U, NonLVal::MakeVal(BasicVals, size, U->getType())); - - Nodify(Dst, U, Pred, St); -} - -void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { - - if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) { - Dst.Add(Pred); - return; - } - - Ex = Ex->IgnoreParens(); - - if (isa(Ex)) { - Dst.Add(Pred); - return; - } - - if (UnaryOperator* U = dyn_cast(Ex)) - if (U->getOpcode() == UnaryOperator::Deref) { - VisitDeref(U, Pred, Dst, true); - return; - } - - Visit(Ex, Pred, Dst); -} - -void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, - GRExprEngine::NodeTy* Pred, - GRExprEngine::NodeSet& Dst) { - NodeSet S1; - - if (B->isAssignmentOp()) - VisitLVal(B->getLHS(), Pred, S1); - else - Visit(B->getLHS(), Pred, S1); - - for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { - - NodeTy* N1 = *I1; - - // When getting the value for the LHS, check if we are in an assignment. - // In such cases, we want to (initially) treat the LHS as an LVal, - // so we use GetLVal instead of GetRVal so that DeclRefExpr's are - // evaluated to LValDecl's instead of to an NonLVal. - - RVal LeftV = B->isAssignmentOp() ? GetLVal(GetState(N1), B->getLHS()) - : GetRVal(GetState(N1), B->getLHS()); - - // Visit the RHS... - - NodeSet S2; - Visit(B->getRHS(), N1, S2); - - // Process the binary operator. - - for (NodeSet::iterator I2 = S2.begin(), E2 = S2.end(); I2 != E2; ++I2) { - - NodeTy* N2 = *I2; - ValueState* St = GetState(N2); - Expr* RHS = B->getRHS(); - RVal RightV = GetRVal(St, RHS); - - BinaryOperator::Opcode Op = B->getOpcode(); - - if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem) - && RHS->getType()->isIntegerType()) { - - // Check if the denominator is undefined. - - if (!RightV.isUnknown()) { - - if (RightV.isUndef()) { - NodeTy* DivUndef = Builder->generateNode(B, St, N2); - - if (DivUndef) { - DivUndef->markAsSink(); - ExplicitBadDivides.insert(DivUndef); - } - - continue; - } - - // Check for divide/remainder-by-zero. - // - // First, "assume" that the denominator is 0 or undefined. - - bool isFeasibleZero = false; - ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero); - - // Second, "assume" that the denominator cannot be 0. - - bool isFeasibleNotZero = false; - St = Assume(St, RightV, true, isFeasibleNotZero); - - // Create the node for the divide-by-zero (if it occurred). - - if (isFeasibleZero) - if (NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2)) { - DivZeroNode->markAsSink(); - - if (isFeasibleNotZero) - ImplicitBadDivides.insert(DivZeroNode); - else - ExplicitBadDivides.insert(DivZeroNode); - - } - - if (!isFeasibleNotZero) - continue; - } - - // Fall-through. The logic below processes the divide. - } - - - if (Op <= BinaryOperator::Or) { - - // Process non-assignements except commas or short-circuited - // logical expressions (LAnd and LOr). - - RVal Result = EvalBinOp(Op, LeftV, RightV); - - if (Result.isUnknown()) { - Dst.Add(N2); - continue; - } - - if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) { - - // The operands were not undefined, but the result is undefined. - - if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) { - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - - continue; - } - - Nodify(Dst, B, N2, SetRVal(St, B, Result)); - continue; - } - - // Process assignments. - - switch (Op) { - - case BinaryOperator::Assign: { - - // Simple assignments. - - if (LeftV.isUndef()) { - HandleUndefinedStore(B, N2); - continue; - } - - // EXPERIMENTAL: "Conjured" symbols. - - if (RightV.isUnknown()) { - unsigned Count = Builder->getCurrentBlockCount(); - SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count); - - RightV = B->getRHS()->getType()->isPointerType() - ? cast(lval::SymbolVal(Sym)) - : cast(nonlval::SymbolVal(Sym)); - } - - // Even if the LHS evaluates to an unknown L-Value, the entire - // expression still evaluates to the RHS. - - if (LeftV.isUnknown()) { - St = SetRVal(St, B, RightV); - break; - } - - // Simulate the effects of a "store": bind the value of the RHS - // to the L-Value represented by the LHS. - - St = SetRVal(SetRVal(St, B, RightV), cast(LeftV), RightV); - break; - } - - // Compound assignment operators. - - default: { - - assert (B->isCompoundAssignmentOp()); - - if (Op >= BinaryOperator::AndAssign) - ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And); - else - ((int&) Op) -= BinaryOperator::MulAssign; - - // Check if the LHS is undefined. - - if (LeftV.isUndef()) { - HandleUndefinedStore(B, N2); - continue; - } - - if (LeftV.isUnknown()) { - assert (isa(GetRVal(St, B))); - Dst.Add(N2); - continue; - } - - // At this pointer we know that the LHS evaluates to an LVal - // that is neither "Unknown" or "Undefined." - - LVal LeftLV = cast(LeftV); - - // Fetch the value of the LHS (the value of the variable, etc.). - - RVal V = GetRVal(GetState(N1), LeftLV, B->getLHS()->getType()); - - // Propagate undefined value (left-side). We - // propogate undefined values for the RHS below when - // we also check for divide-by-zero. - - if (V.isUndef()) { - St = SetRVal(St, B, V); - break; - } - - // Propagate unknown values. - - if (V.isUnknown()) { - // The value bound to LeftV is unknown. Thus we just - // propagate the current node (as "B" is already bound to nothing). - assert (isa(GetRVal(St, B))); - Dst.Add(N2); - continue; - } - - if (RightV.isUnknown()) { - assert (isa(GetRVal(St, B))); - St = SetRVal(St, LeftLV, UnknownVal()); - break; - } - - // At this point: - // - // The LHS is not Undef/Unknown. - // The RHS is not Unknown. - - // Get the computation type. - QualType CTy = cast(B)->getComputationType(); - - // Perform promotions. - V = EvalCast(V, CTy); - RightV = EvalCast(RightV, CTy); - - // Evaluate operands and promote to result type. - - if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem) - && RHS->getType()->isIntegerType()) { - - // Check if the denominator is undefined. - - if (RightV.isUndef()) { - NodeTy* DivUndef = Builder->generateNode(B, St, N2); - - if (DivUndef) { - DivUndef->markAsSink(); - ExplicitBadDivides.insert(DivUndef); - } - - continue; - } - - // First, "assume" that the denominator is 0. - - bool isFeasibleZero = false; - ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero); - - // Second, "assume" that the denominator cannot be 0. - - bool isFeasibleNotZero = false; - St = Assume(St, RightV, true, isFeasibleNotZero); - - // Create the node for the divide-by-zero error (if it occurred). - - if (isFeasibleZero) { - NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2); - - if (DivZeroNode) { - DivZeroNode->markAsSink(); - - if (isFeasibleNotZero) - ImplicitBadDivides.insert(DivZeroNode); - else - ExplicitBadDivides.insert(DivZeroNode); - } - } - - if (!isFeasibleNotZero) - continue; - - // Fall-through. The logic below processes the divide. - } - else { - - // Propagate undefined values (right-side). - - if (RightV.isUndef()) { - St = SetRVal(SetRVal(St, B, RightV), LeftLV, RightV); - break; - } - - } - - RVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType()); - - if (Result.isUndef()) { - - // The operands were not undefined, but the result is undefined. - - if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) { - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - - continue; - } - - St = SetRVal(SetRVal(St, B, Result), LeftLV, Result); - } - } - - Nodify(Dst, B, N2, St); - } - } -} - -void GRExprEngine::HandleUndefinedStore(Stmt* S, NodeTy* Pred) { - NodeTy* N = Builder->generateNode(S, GetState(Pred), Pred); - N->markAsSink(); - UndefStores.insert(N); -} - -void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { - - // FIXME: add metadata to the CFG so that we can disable - // this check when we KNOW that there is no block-level subexpression. - // The motivation is that this check requires a hashtable lookup. - - if (S != CurrentStmt && getCFG().isBlkExpr(S)) { - Dst.Add(Pred); - return; - } - - switch (S->getStmtClass()) { - - default: - // Cases we intentionally have "default" handle: - // AddrLabelExpr, IntegerLiteral, CharacterLiteral - - Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. - break; - - case Stmt::BinaryOperatorClass: { - BinaryOperator* B = cast(S); - - if (B->isLogicalOp()) { - VisitLogicalExpr(B, Pred, Dst); - break; - } - else if (B->getOpcode() == BinaryOperator::Comma) { - ValueState* St = GetState(Pred); - Nodify(Dst, B, Pred, SetRVal(St, B, GetRVal(St, B->getRHS()))); - break; - } - - VisitBinaryOperator(cast(S), Pred, Dst); - break; - } - - case Stmt::CallExprClass: { - CallExpr* C = cast(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); - break; - } - - case Stmt::CastExprClass: { - CastExpr* C = cast(S); - VisitCast(C, C->getSubExpr(), Pred, Dst); - break; - } - - // FIXME: ChooseExpr is really a constant. We need to fix - // the CFG do not model them as explicit control-flow. - - case Stmt::ChooseExprClass: { // __builtin_choose_expr - ChooseExpr* C = cast(S); - VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); - break; - } - - case Stmt::CompoundAssignOperatorClass: - VisitBinaryOperator(cast(S), Pred, Dst); - break; - - case Stmt::ConditionalOperatorClass: { // '?' operator - ConditionalOperator* C = cast(S); - VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); - break; - } - - case Stmt::DeclRefExprClass: - VisitDeclRefExpr(cast(S), Pred, Dst); - break; - - case Stmt::DeclStmtClass: - VisitDeclStmt(cast(S), Pred, Dst); - break; - - case Stmt::ImplicitCastExprClass: { - ImplicitCastExpr* C = cast(S); - VisitCast(C, C->getSubExpr(), Pred, Dst); - break; - } - - case Stmt::ParenExprClass: - Visit(cast(S)->getSubExpr(), Pred, Dst); - break; - - case Stmt::SizeOfAlignOfTypeExprClass: - VisitSizeOfAlignOfTypeExpr(cast(S), Pred, Dst); - break; - - case Stmt::StmtExprClass: { - StmtExpr* SE = cast(S); - - ValueState* St = GetState(Pred); - - // FIXME: Not certain if we can have empty StmtExprs. If so, we should - // probably just remove these from the CFG. - assert (!SE->getSubStmt()->body_empty()); - - if (Expr* LastExpr = dyn_cast(*SE->getSubStmt()->body_rbegin())) - Nodify(Dst, SE, Pred, SetRVal(St, SE, GetRVal(St, LastExpr))); - else - Dst.Add(Pred); - - break; - } - - // FIXME: We may wish to always bind state to ReturnStmts so - // that users can quickly query what was the state at the - // exit points of a function. - - case Stmt::ReturnStmtClass: { - if (Expr* R = cast(S)->getRetValue()) - Visit(R, Pred, Dst); - else - Dst.Add(Pred); - - break; - } - - case Stmt::UnaryOperatorClass: { - UnaryOperator* U = cast(S); - - switch (U->getOpcode()) { - case UnaryOperator::Deref: VisitDeref(U, Pred, Dst); break; - case UnaryOperator::Plus: Visit(U->getSubExpr(), Pred, Dst); break; - case UnaryOperator::SizeOf: VisitSizeOfExpr(U, Pred, Dst); break; - default: VisitUnaryOperator(U, Pred, Dst); break; - } - - break; - } - } -} - -//===----------------------------------------------------------------------===// -// "Assume" logic. -//===----------------------------------------------------------------------===// - -ValueState* GRExprEngine::Assume(ValueState* St, LVal Cond, - bool Assumption, - bool& isFeasible) { - switch (Cond.getSubKind()) { - default: - assert (false && "'Assume' not implemented for this LVal."); - return St; - - case lval::SymbolValKind: - if (Assumption) - return AssumeSymNE(St, cast(Cond).getSymbol(), - BasicVals.getZeroWithPtrWidth(), isFeasible); - else - return AssumeSymEQ(St, cast(Cond).getSymbol(), - BasicVals.getZeroWithPtrWidth(), isFeasible); - - - case lval::DeclValKind: - case lval::FuncValKind: - case lval::GotoLabelKind: - isFeasible = Assumption; - return St; - - case lval::ConcreteIntKind: { - bool b = cast(Cond).getValue() != 0; - isFeasible = b ? Assumption : !Assumption; - return St; - } - } -} - -ValueState* GRExprEngine::Assume(ValueState* St, NonLVal Cond, - bool Assumption, - bool& isFeasible) { - switch (Cond.getSubKind()) { - default: - assert (false && "'Assume' not implemented for this NonLVal."); - return St; - - - case nonlval::SymbolValKind: { - nonlval::SymbolVal& SV = cast(Cond); - SymbolID sym = SV.getSymbol(); - - if (Assumption) - return AssumeSymNE(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)), - isFeasible); - else - return AssumeSymEQ(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)), - isFeasible); - } - - case nonlval::SymIntConstraintValKind: - return - AssumeSymInt(St, Assumption, - cast(Cond).getConstraint(), - isFeasible); - - case nonlval::ConcreteIntKind: { - bool b = cast(Cond).getValue() != 0; - isFeasible = b ? Assumption : !Assumption; - return St; - } - } -} - -ValueState* -GRExprEngine::AssumeSymNE(ValueState* St, SymbolID sym, - const llvm::APSInt& V, bool& isFeasible) { - - // First, determine if sym == X, where X != V. - if (const llvm::APSInt* X = St->getSymVal(sym)) { - isFeasible = *X != V; - return St; - } - - // Second, determine if sym != V. - if (St->isNotEqual(sym, V)) { - isFeasible = true; - return St; - } - - // If we reach here, sym is not a constant and we don't know if it is != V. - // Make that assumption. - - isFeasible = true; - return StateMgr.AddNE(St, sym, V); -} - -ValueState* -GRExprEngine::AssumeSymEQ(ValueState* St, SymbolID sym, - const llvm::APSInt& V, bool& isFeasible) { - - // First, determine if sym == X, where X != V. - if (const llvm::APSInt* X = St->getSymVal(sym)) { - isFeasible = *X == V; - return St; - } - - // Second, determine if sym != V. - if (St->isNotEqual(sym, V)) { - isFeasible = false; - return St; - } - - // If we reach here, sym is not a constant and we don't know if it is == V. - // Make that assumption. - - isFeasible = true; - return StateMgr.AddEQ(St, sym, V); -} - -ValueState* -GRExprEngine::AssumeSymInt(ValueState* St, bool Assumption, - const SymIntConstraint& C, bool& isFeasible) { - - switch (C.getOpcode()) { - default: - // No logic yet for other operators. - isFeasible = true; - return St; - - case BinaryOperator::EQ: - if (Assumption) - return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible); - else - return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible); - - case BinaryOperator::NE: - if (Assumption) - return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible); - else - return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible); - } -} - -//===----------------------------------------------------------------------===// -// Visualization. -//===----------------------------------------------------------------------===// - -#ifndef NDEBUG -static GRExprEngine* GraphPrintCheckerState; -static SourceManager* GraphPrintSourceManager; -static ValueState::CheckerStatePrinter* GraphCheckerStatePrinter; - -namespace llvm { -template<> -struct VISIBILITY_HIDDEN DOTGraphTraits : - public DefaultDOTGraphTraits { - - static void PrintVarBindings(std::ostream& Out, ValueState* St) { - - Out << "Variables:\\l"; - - bool isFirst = true; - - for (ValueState::vb_iterator I=St->vb_begin(), E=St->vb_end(); I!=E;++I) { - - if (isFirst) - isFirst = false; - else - Out << "\\l"; - - Out << ' ' << I.getKey()->getName() << " : "; - I.getData().print(Out); - } - - } - - - static void PrintSubExprBindings(std::ostream& Out, ValueState* St){ - - bool isFirst = true; - - for (ValueState::seb_iterator I=St->seb_begin(), E=St->seb_end();I!=E;++I) { - - if (isFirst) { - Out << "\\l\\lSub-Expressions:\\l"; - isFirst = false; - } - else - Out << "\\l"; - - Out << " (" << (void*) I.getKey() << ") "; - I.getKey()->printPretty(Out); - Out << " : "; - I.getData().print(Out); - } - } - - static void PrintBlkExprBindings(std::ostream& Out, ValueState* St){ - - bool isFirst = true; - - for (ValueState::beb_iterator I=St->beb_begin(), E=St->beb_end(); I!=E;++I){ - if (isFirst) { - Out << "\\l\\lBlock-level Expressions:\\l"; - isFirst = false; - } - else - Out << "\\l"; - - Out << " (" << (void*) I.getKey() << ") "; - I.getKey()->printPretty(Out); - Out << " : "; - I.getData().print(Out); - } - } - - static void PrintEQ(std::ostream& Out, ValueState* St) { - ValueState::ConstEqTy CE = St->ConstEq; - - if (CE.isEmpty()) - return; - - Out << "\\l\\|'==' constraints:"; - - for (ValueState::ConstEqTy::iterator I=CE.begin(), E=CE.end(); I!=E;++I) - Out << "\\l $" << I.getKey() << " : " << I.getData()->toString(); - } - - static void PrintNE(std::ostream& Out, ValueState* St) { - ValueState::ConstNotEqTy NE = St->ConstNotEq; - - if (NE.isEmpty()) - return; - - Out << "\\l\\|'!=' constraints:"; - - for (ValueState::ConstNotEqTy::iterator I=NE.begin(), EI=NE.end(); - I != EI; ++I){ - - Out << "\\l $" << I.getKey() << " : "; - bool isFirst = true; - - ValueState::IntSetTy::iterator J=I.getData().begin(), - EJ=I.getData().end(); - for ( ; J != EJ; ++J) { - if (isFirst) isFirst = false; - else Out << ", "; - - Out << (*J)->toString(); - } - } - } - - static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) { - - if (GraphPrintCheckerState->isImplicitNullDeref(N) || - GraphPrintCheckerState->isExplicitNullDeref(N) || - GraphPrintCheckerState->isUndefDeref(N) || - GraphPrintCheckerState->isUndefStore(N) || - GraphPrintCheckerState->isUndefControlFlow(N) || - GraphPrintCheckerState->isExplicitBadDivide(N) || - GraphPrintCheckerState->isImplicitBadDivide(N) || - GraphPrintCheckerState->isUndefResult(N) || - GraphPrintCheckerState->isBadCall(N) || - GraphPrintCheckerState->isUndefArg(N)) - return "color=\"red\",style=\"filled\""; - - if (GraphPrintCheckerState->isNoReturnCall(N)) - return "color=\"blue\",style=\"filled\""; - - return ""; - } - - static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) { - std::ostringstream Out; - - // Program Location. - ProgramPoint Loc = N->getLocation(); - - switch (Loc.getKind()) { - case ProgramPoint::BlockEntranceKind: - Out << "Block Entrance: B" - << cast(Loc).getBlock()->getBlockID(); - break; - - case ProgramPoint::BlockExitKind: - assert (false); - break; - - case ProgramPoint::PostStmtKind: { - const PostStmt& L = cast(Loc); - Stmt* S = L.getStmt(); - SourceLocation SLoc = S->getLocStart(); - - Out << S->getStmtClassName() << ' ' << (void*) S << ' '; - S->printPretty(Out); - - if (SLoc.isFileID()) { - Out << "\\lline=" - << GraphPrintSourceManager->getLineNumber(SLoc) << " col=" - << GraphPrintSourceManager->getColumnNumber(SLoc) << "\\l"; - } - - if (GraphPrintCheckerState->isImplicitNullDeref(N)) - Out << "\\|Implicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isExplicitNullDeref(N)) - Out << "\\|Explicit-Null Dereference.\\l"; - else if (GraphPrintCheckerState->isUndefDeref(N)) - Out << "\\|Dereference of undefialied value.\\l"; - else if (GraphPrintCheckerState->isUndefStore(N)) - Out << "\\|Store to Undefined LVal."; - else if (GraphPrintCheckerState->isExplicitBadDivide(N)) - Out << "\\|Explicit divide-by zero or undefined value."; - else if (GraphPrintCheckerState->isImplicitBadDivide(N)) - Out << "\\|Implicit divide-by zero or undefined value."; - else if (GraphPrintCheckerState->isUndefResult(N)) - Out << "\\|Result of operation is undefined."; - else if (GraphPrintCheckerState->isNoReturnCall(N)) - Out << "\\|Call to function marked \"noreturn\"."; - else if (GraphPrintCheckerState->isBadCall(N)) - Out << "\\|Call to NULL/Undefined."; - else if (GraphPrintCheckerState->isUndefArg(N)) - Out << "\\|Argument in call is undefined"; - - break; - } - - default: { - const BlockEdge& E = cast(Loc); - Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" - << E.getDst()->getBlockID() << ')'; - - if (Stmt* T = E.getSrc()->getTerminator()) { - - SourceLocation SLoc = T->getLocStart(); - - Out << "\\|Terminator: "; - - E.getSrc()->printTerminator(Out); - - if (SLoc.isFileID()) { - Out << "\\lline=" - << GraphPrintSourceManager->getLineNumber(SLoc) << " col=" - << GraphPrintSourceManager->getColumnNumber(SLoc); - } - - if (isa(T)) { - Stmt* Label = E.getDst()->getLabel(); - - if (Label) { - if (CaseStmt* C = dyn_cast(Label)) { - Out << "\\lcase "; - C->getLHS()->printPretty(Out); - - if (Stmt* RHS = C->getRHS()) { - Out << " .. "; - RHS->printPretty(Out); - } - - Out << ":"; - } - else { - assert (isa(Label)); - Out << "\\ldefault:"; - } - } - else - Out << "\\l(implicit) default:"; - } - else if (isa(T)) { - // FIXME - } - else { - Out << "\\lCondition: "; - if (*E.getSrc()->succ_begin() == E.getDst()) - Out << "true"; - else - Out << "false"; - } - - Out << "\\l"; - } - - if (GraphPrintCheckerState->isUndefControlFlow(N)) { - Out << "\\|Control-flow based on\\lUndefined value.\\l"; - } - } - } - - Out << "\\|StateID: " << (void*) N->getState() << "\\|"; - - N->getState()->printDOT(Out, GraphCheckerStatePrinter); - - Out << "\\l"; - return Out.str(); - } -}; -} // end llvm namespace -#endif - -#ifndef NDEBUG - -template -GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; } - -template <> -GRExprEngine::NodeTy* -GetGraphNode::iterator> - (llvm::DenseMap::iterator I) { - return I->first; -} - -template -static void AddSources(llvm::SmallVector& Sources, - ITERATOR I, ITERATOR E) { - - llvm::SmallPtrSet CachedSources; - - for ( ; I != E; ++I ) { - GRExprEngine::NodeTy* N = GetGraphNode(I); - void* p = N->getLocation().getRawData(); - - if (CachedSources.count(p)) - continue; - - CachedSources.insert(p); - - Sources.push_back(N); - } -} -#endif - -void GRExprEngine::ViewGraph(bool trim) { -#ifndef NDEBUG - if (trim) { - llvm::SmallVector Src; - AddSources(Src, null_derefs_begin(), null_derefs_end()); - AddSources(Src, undef_derefs_begin(), undef_derefs_end()); - AddSources(Src, explicit_bad_divides_begin(), explicit_bad_divides_end()); - AddSources(Src, undef_results_begin(), undef_results_end()); - AddSources(Src, bad_calls_begin(), bad_calls_end()); - AddSources(Src, undef_arg_begin(), undef_arg_end()); - AddSources(Src, undef_branches_begin(), undef_branches_end()); - - ViewGraph(&Src[0], &Src[0]+Src.size()); - } - else { - GraphPrintCheckerState = this; - GraphPrintSourceManager = &getContext().getSourceManager(); - GraphCheckerStatePrinter = TF->getCheckerStatePrinter(); - - llvm::ViewGraph(*G.roots_begin(), "GRExprEngine"); - - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; - GraphCheckerStatePrinter = NULL; - } -#endif -} - -void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) { -#ifndef NDEBUG - GraphPrintCheckerState = this; - GraphPrintSourceManager = &getContext().getSourceManager(); - GraphCheckerStatePrinter = TF->getCheckerStatePrinter(); - - GRExprEngine::GraphTy* TrimmedG = G.Trim(Beg, End); - - if (!TrimmedG) - llvm::cerr << "warning: Trimmed ExplodedGraph is empty.\n"; - else { - llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine"); - delete TrimmedG; - } - - GraphPrintCheckerState = NULL; - GraphPrintSourceManager = NULL; - GraphCheckerStatePrinter = NULL; -#endif -} diff --git a/clang/Analysis/GRSimpleVals.cpp b/clang/Analysis/GRSimpleVals.cpp deleted file mode 100644 index 3777d53bf0b..00000000000 --- a/clang/Analysis/GRSimpleVals.cpp +++ /dev/null @@ -1,462 +0,0 @@ -// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- 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 GRSimpleVals, a sub-class of GRTransferFuncs that -// provides transfer functions for performing simple value tracking with -// limited support for symbolics. -// -//===----------------------------------------------------------------------===// - -#include "GRSimpleVals.h" -#include "clang/Analysis/PathSensitive/ValueState.h" -#include "clang/Basic/Diagnostic.h" -#include - -using namespace clang; - -namespace clang { - -template -static inline ProgramPoint GetLocation(ITERATOR I) { - return (*I)->getLocation(); -} - -template <> -inline ProgramPoint GetLocation(GRExprEngine::undef_arg_iterator I) { - return I->first->getLocation(); -} - -static inline Stmt* GetStmt(const ProgramPoint& P) { - if (const PostStmt* PS = dyn_cast(&P)) { - return PS->getStmt(); - } - else if (const BlockEdge* BE = dyn_cast(&P)) { - return BE->getSrc()->getTerminator(); - } - - assert (false && "Unsupported ProgramPoint."); - return NULL; -} - -template -static void EmitDiag(Diagnostic& Diag, SourceManager& SrcMgr, - unsigned ErrorDiag, ITERATOR I) { - - Stmt* S = GetStmt(GetLocation(I)); - Diag.Report(FullSourceLoc(S->getLocStart(), SrcMgr), ErrorDiag); -} - - -template <> -static void EmitDiag(Diagnostic& Diag, SourceManager& SrcMgr, - unsigned ErrorDiag, GRExprEngine::undef_arg_iterator I) { - - Stmt* S1 = GetStmt(GetLocation(I)); - Expr* E2 = cast(I->second); - - SourceLocation Loc = S1->getLocStart(); - SourceRange R = E2->getSourceRange(); - Diag.Report(FullSourceLoc(Loc, SrcMgr), ErrorDiag, 0, 0, &R, 1); -} - -template -void EmitWarning(Diagnostic& Diag, SourceManager& SrcMgr, - ITERATOR I, ITERATOR E, const char* msg) { - - std::ostringstream Out; - Out << "[CHECKER] " << msg; - msg = Out.str().c_str(); - - bool isFirst = true; - unsigned ErrorDiag = 0; - llvm::SmallPtrSet CachedErrors; - - for (; I != E; ++I) { - - if (isFirst) { - isFirst = false; - ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, msg); - } - else { - - // HACK: Cache the location of the error. Don't emit the same - // warning for the same error type that occurs at the same program - // location but along a different path. - void* p = GetLocation(I).getRawData(); - - if (CachedErrors.count(p)) - continue; - - CachedErrors.insert(p); - } - - EmitDiag(Diag, SrcMgr, ErrorDiag, I); - } -} - -unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, - Diagnostic& Diag, bool Visualize, bool TrimGraph) { - - if (Diag.hasErrorOccurred()) - return 0; - - GRCoreEngine Eng(cfg, CD, Ctx); - GRExprEngine* CheckerState = &Eng.getCheckerState(); - GRSimpleVals GRSV; - CheckerState->setTransferFunctions(GRSV); - - // Execute the worklist algorithm. - Eng.ExecuteWorkList(100000); - - SourceManager& SrcMgr = Ctx.getSourceManager(); - - EmitWarning(Diag, SrcMgr, - CheckerState->null_derefs_begin(), - CheckerState->null_derefs_end(), - "NULL pointer is dereferenced after it is checked for NULL."); - - EmitWarning(Diag, SrcMgr, - CheckerState->undef_derefs_begin(), - CheckerState->undef_derefs_end(), - "Dereference of undefined value."); - - EmitWarning(Diag, SrcMgr, - CheckerState->undef_derefs_begin(), - CheckerState->undef_derefs_end(), - "Dereference of undefined value."); - - EmitWarning(Diag, SrcMgr, - CheckerState->explicit_bad_divides_begin(), - CheckerState->explicit_bad_divides_end(), - "Division by zero/undefined value."); - - EmitWarning(Diag, SrcMgr, - CheckerState->undef_results_begin(), - CheckerState->undef_results_end(), - "Result of operation is undefined."); - - EmitWarning(Diag, SrcMgr, - CheckerState->bad_calls_begin(), - CheckerState->bad_calls_end(), - "Call using a NULL or undefined function pointer value."); - - EmitWarning(Diag, SrcMgr, - CheckerState->undef_arg_begin(), - CheckerState->undef_arg_end(), - "Pass-by-value argument in function or message expression is undefined."); - - EmitWarning(Diag, SrcMgr, - CheckerState->undef_branches_begin(), - CheckerState->undef_branches_end(), - "Branch condition evaluates to an uninitialized value."); - -#ifndef NDEBUG - if (Visualize) CheckerState->ViewGraph(TrimGraph); -#endif - - return Eng.getGraph().size(); -} - -} // end clang namespace - -//===----------------------------------------------------------------------===// -// Transfer function for Casts. -//===----------------------------------------------------------------------===// - -RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLVal X, QualType T) { - - if (!isa(X)) - return UnknownVal(); - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - llvm::APSInt V = cast(X).getValue(); - V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType() - || T->isObjCQualifiedIdType()); - V.extOrTrunc(Eng.getContext().getTypeSize(T)); - - if (T->isPointerType()) - return lval::ConcreteInt(BasicVals.getValue(V)); - else - return nonlval::ConcreteInt(BasicVals.getValue(V)); -} - -// Casts. - -RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, LVal X, QualType T) { - - if (T->isPointerType() || T->isReferenceType() || T->isObjCQualifiedIdType()) - return X; - - assert (T->isIntegerType()); - - if (!isa(X)) - return UnknownVal(); - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - llvm::APSInt V = cast(X).getValue(); - V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType()); - V.extOrTrunc(Eng.getContext().getTypeSize(T)); - - return nonlval::ConcreteInt(BasicVals.getValue(V)); -} - -// Unary operators. - -RVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLVal X){ - - switch (X.getSubKind()) { - - case nonlval::ConcreteIntKind: - return cast(X).EvalMinus(Eng.getBasicVals(), U); - - default: - return UnknownVal(); - } -} - -RVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLVal X) { - - switch (X.getSubKind()) { - - case nonlval::ConcreteIntKind: - return cast(X).EvalComplement(Eng.getBasicVals()); - - default: - return UnknownVal(); - } -} - -// Binary operators. - -RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, - NonLVal L, NonLVal R) { - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - while (1) { - - switch (L.getSubKind()) { - default: - return UnknownVal(); - - case nonlval::ConcreteIntKind: - - if (isa(R)) { - const nonlval::ConcreteInt& L_CI = cast(L); - const nonlval::ConcreteInt& R_CI = cast(R); - return L_CI.EvalBinOp(BasicVals, Op, R_CI); - } - else { - NonLVal tmp = R; - R = L; - L = tmp; - continue; - } - - case nonlval::SymbolValKind: { - - if (isa(R)) { - const SymIntConstraint& C = - BasicVals.getConstraint(cast(L).getSymbol(), Op, - cast(R).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - else - return UnknownVal(); - } - } - } -} - - -// Binary Operators (except assignments and comma). - -RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, - LVal L, LVal R) { - - switch (Op) { - - default: - return UnknownVal(); - - case BinaryOperator::EQ: - return EvalEQ(Eng, L, R); - - case BinaryOperator::NE: - return EvalNE(Eng, L, R); - } -} - -// Pointer arithmetic. - -RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, - LVal L, NonLVal R) { - return UnknownVal(); -} - -// Equality operators for LVals. - -RVal GRSimpleVals::EvalEQ(GRExprEngine& Eng, LVal L, LVal R) { - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - switch (L.getSubKind()) { - - default: - assert(false && "EQ not implemented for this LVal."); - return UnknownVal(); - - case lval::ConcreteIntKind: - - if (isa(R)) { - bool b = cast(L).getValue() == - cast(R).getValue(); - - return NonLVal::MakeIntTruthVal(BasicVals, b); - } - else if (isa(R)) { - - const SymIntConstraint& C = - BasicVals.getConstraint(cast(R).getSymbol(), - BinaryOperator::EQ, - cast(L).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - break; - - case lval::SymbolValKind: { - - if (isa(R)) { - const SymIntConstraint& C = - BasicVals.getConstraint(cast(L).getSymbol(), - BinaryOperator::EQ, - cast(R).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - // FIXME: Implement == for lval Symbols. This is mainly useful - // in iterator loops when traversing a buffer, e.g. while(z != zTerm). - // Since this is not useful for many checkers we'll punt on this for - // now. - - return UnknownVal(); - } - - case lval::DeclValKind: - case lval::FuncValKind: - case lval::GotoLabelKind: - return NonLVal::MakeIntTruthVal(BasicVals, L == R); - } - - return NonLVal::MakeIntTruthVal(BasicVals, false); -} - -RVal GRSimpleVals::EvalNE(GRExprEngine& Eng, LVal L, LVal R) { - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - switch (L.getSubKind()) { - - default: - assert(false && "NE not implemented for this LVal."); - return UnknownVal(); - - case lval::ConcreteIntKind: - - if (isa(R)) { - bool b = cast(L).getValue() != - cast(R).getValue(); - - return NonLVal::MakeIntTruthVal(BasicVals, b); - } - else if (isa(R)) { - const SymIntConstraint& C = - BasicVals.getConstraint(cast(R).getSymbol(), - BinaryOperator::NE, - cast(L).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - break; - - case lval::SymbolValKind: { - if (isa(R)) { - const SymIntConstraint& C = - BasicVals.getConstraint(cast(L).getSymbol(), - BinaryOperator::NE, - cast(R).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - // FIXME: Implement != for lval Symbols. This is mainly useful - // in iterator loops when traversing a buffer, e.g. while(z != zTerm). - // Since this is not useful for many checkers we'll punt on this for - // now. - - return UnknownVal(); - - break; - } - - case lval::DeclValKind: - case lval::FuncValKind: - case lval::GotoLabelKind: - return NonLVal::MakeIntTruthVal(BasicVals, L != R); - } - - return NonLVal::MakeIntTruthVal(BasicVals, true); -} - -//===----------------------------------------------------------------------===// -// Transfer function for Function Calls. -//===----------------------------------------------------------------------===// - -void GRSimpleVals::EvalCall(ExplodedNodeSet& Dst, - GRExprEngine& Eng, - GRStmtNodeBuilder& Builder, - CallExpr* CE, LVal L, - ExplodedNode* Pred) { - - ValueStateManager& StateMgr = Eng.getStateManager(); - ValueState* St = Builder.GetState(Pred); - - // Invalidate all arguments passed in by reference (LVals). - - for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - - RVal V = StateMgr.GetRVal(St, *I); - - if (isa(V)) - St = StateMgr.SetRVal(St, cast(V), UnknownVal()); - } - - // Make up a symbol for the return value of this function. - - if (CE->getType() != Eng.getContext().VoidTy) { - unsigned Count = Builder.getCurrentBlockCount(); - SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); - - RVal X = CE->getType()->isPointerType() - ? cast(lval::SymbolVal(Sym)) - : cast(nonlval::SymbolVal(Sym)); - - St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false); - } - - Builder.Nodify(Dst, CE, Pred, St); -} diff --git a/clang/Analysis/GRSimpleVals.h b/clang/Analysis/GRSimpleVals.h deleted file mode 100644 index 2b3d0fd00a2..00000000000 --- a/clang/Analysis/GRSimpleVals.h +++ /dev/null @@ -1,71 +0,0 @@ -// GRSimpleVals.h - Transfer functions for tracking simple values -*- 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 GRSimpleVals, a sub-class of GRTransferFuncs that -// provides transfer functions for performing simple value tracking with -// limited support for symbolics. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS -#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS - -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" - -namespace clang { - -class GRSimpleVals : public GRTransferFuncs { -public: - GRSimpleVals() {} - virtual ~GRSimpleVals() {} - - // Casts. - - virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT); - virtual RVal EvalCast(GRExprEngine& Engine, LVal V, QualType CastT); - - // Unary Operators. - - virtual RVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLVal X); - - virtual RVal EvalComplement(GRExprEngine& Engine, NonLVal X); - - // Binary Operators. - - virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, - NonLVal L, NonLVal R); - - virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, - LVal L, LVal R); - - // Pointer arithmetic. - - virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, - LVal L, NonLVal R); - - // Calls. - - virtual void EvalCall(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, LVal L, - ExplodedNode* Pred); - -protected: - - // Equality operators for LVals. - - RVal EvalEQ(GRExprEngine& Engine, LVal L, LVal R); - RVal EvalNE(GRExprEngine& Engine, LVal L, LVal R); -}; - -} // end clang namespace - -#endif diff --git a/clang/Analysis/LiveVariables.cpp b/clang/Analysis/LiveVariables.cpp deleted file mode 100644 index e59a4885911..00000000000 --- a/clang/Analysis/LiveVariables.cpp +++ /dev/null @@ -1,246 +0,0 @@ -//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// details. -// -//===----------------------------------------------------------------------===// -// -// This file implements Live Variables analysis for source-level CFGs. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Basic/SourceManager.h" -#include "clang/AST/Expr.h" -#include "clang/AST/CFG.h" -#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/FlowSensitive/DataflowSolver.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/Compiler.h" - -#include -#include - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Dataflow initialization logic. -//===----------------------------------------------------------------------===// - -namespace { -class VISIBILITY_HIDDEN RegisterDecls - : public CFGRecStmtDeclVisitor { - - LiveVariables::AnalysisDataTy& AD; -public: - RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} - void VisitVarDecl(VarDecl* VD) { AD.Register(VD); } - CFG& getCFG() { return AD.getCFG(); } -}; -} // end anonymous namespace - - -LiveVariables::LiveVariables(CFG& cfg) { - // Register all referenced VarDecls. - getAnalysisData().setCFG(&cfg); - RegisterDecls R(getAnalysisData()); - cfg.VisitBlockStmts(R); -} - -//===----------------------------------------------------------------------===// -// Transfer functions. -//===----------------------------------------------------------------------===// - -namespace { - -static const bool Alive = true; -static const bool Dead = false; - -class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor{ - LiveVariables::AnalysisDataTy& AD; - LiveVariables::ValTy LiveState; -public: - TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} - - LiveVariables::ValTy& getVal() { return LiveState; } - CFG& getCFG() { return AD.getCFG(); } - - void VisitDeclRefExpr(DeclRefExpr* DR); - void VisitBinaryOperator(BinaryOperator* B); - void VisitAssign(BinaryOperator* B); - void VisitDeclStmt(DeclStmt* DS); - void VisitUnaryOperator(UnaryOperator* U); - void Visit(Stmt *S); -}; - -void TransferFuncs::Visit(Stmt *S) { - if (AD.Observer) - AD.Observer->ObserveStmt(S,AD,LiveState); - - if (S == getCurrentBlkStmt()) { - if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead; - StmtVisitor::Visit(S); - } - else if (!getCFG().isBlkExpr(S)) - StmtVisitor::Visit(S); - else - // For block-level expressions, mark that they are live. - LiveState(S,AD) = Alive; -} - -void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { - if (VarDecl* V = dyn_cast(DR->getDecl())) - LiveState(V,AD) = Alive; -} - -void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { - if (B->isAssignmentOp()) VisitAssign(B); - else VisitStmt(B); -} - -void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { - Expr *E = U->getSubExpr(); - - switch (U->getOpcode()) { - case UnaryOperator::SizeOf: return; - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - case UnaryOperator::AddrOf: - // Walk through the subexpressions, blasting through ParenExprs - // until we either find a DeclRefExpr or some non-DeclRefExpr - // expression. - if (DeclRefExpr* DR = dyn_cast(E->IgnoreParens())) - if (VarDecl* VD = dyn_cast(DR->getDecl())) { - // Treat the --/++/& operator as a kill. - LiveState(VD, AD) = Dead; - if (AD.Observer) { AD.Observer->ObserverKill(DR); } - return VisitDeclRefExpr(DR); - } - - // Fall-through. - - default: - return Visit(E); - } -} - -void TransferFuncs::VisitAssign(BinaryOperator* B) { - Expr* LHS = B->getLHS(); - - // Assigning to a variable? - if (DeclRefExpr* DR = dyn_cast(LHS->IgnoreParens())) { - LiveState(DR->getDecl(),AD) = Dead; - if (AD.Observer) { AD.Observer->ObserverKill(DR); } - - // Handle things like +=, etc., which also generate "uses" - // of a variable. Do this just by visiting the subexpression. - if (B->getOpcode() != BinaryOperator::Assign) - VisitDeclRefExpr(DR); - } - else // Not assigning to a variable. Process LHS as usual. - Visit(LHS); - - Visit(B->getRHS()); -} - -void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { - // Declarations effectively "kill" a variable since they cannot - // possibly be live before they are declared. - for (ScopedDecl* D = DS->getDecl(); D != NULL; D = D->getNextDeclarator()) - if (VarDecl* VD = dyn_cast(D)) { - LiveState(D,AD) = Dead; - - if (Expr* Init = VD->getInit()) - Visit(Init); - } -} - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Merge operator: if something is live on any successor block, it is live -// in the current block (a set union). -//===----------------------------------------------------------------------===// - -namespace { -typedef ExprDeclBitVector_Types::Union Merge; -typedef DataflowSolver Solver; -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// External interface to run Liveness analysis. -//===----------------------------------------------------------------------===// - -void LiveVariables::runOnCFG(CFG& cfg) { - Solver S(*this); - S.runOnCFG(cfg); -} - -void LiveVariables::runOnAllBlocks(const CFG& cfg, - LiveVariables::ObserverTy* Obs, - bool recordStmtValues) { - Solver S(*this); - ObserverTy* OldObserver = getAnalysisData().Observer; - getAnalysisData().Observer = Obs; - S.runOnAllBlocks(cfg, recordStmtValues); - getAnalysisData().Observer = OldObserver; -} - -//===----------------------------------------------------------------------===// -// liveness queries -// - -bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const { - DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D); - return i.isValid() ? getBlockData(B).getBit(i) : false; -} - -bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const { - DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D); - return i.isValid() ? Live.getBit(i) : false; -} - -bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const { - return getStmtData(Loc)(StmtVal,getAnalysisData()); -} - -bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const { - return getStmtData(Loc)(D,getAnalysisData()); -} - -//===----------------------------------------------------------------------===// -// printing liveness state for debugging -// - -void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { - const AnalysisDataTy& AD = getAnalysisData(); - - for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), - E = AD.end_decl(); I!=E; ++I) - if (V.getDeclBit(I->second)) { - SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation()); - - fprintf(stderr, " %s <%s:%u:%u>\n", - I->first->getIdentifier()->getName(), - SM.getSourceName(PhysLoc), - SM.getLineNumber(PhysLoc), - SM.getColumnNumber(PhysLoc)); - } -} - -void LiveVariables::dumpBlockLiveness(SourceManager& M) const { - for (BlockDataMapTy::iterator I = getBlockDataMap().begin(), - E = getBlockDataMap().end(); I!=E; ++I) { - fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n", - I->first->getBlockID()); - - dumpLiveness(I->second,M); - } - - fprintf(stderr,"\n"); -} diff --git a/clang/Analysis/Makefile b/clang/Analysis/Makefile deleted file mode 100644 index a106263929e..00000000000 --- a/clang/Analysis/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -##===- clang/Analysis/Makefile -----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements analyses built on top of source-level CFGs. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangAnalysis -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/Analysis/ProgramPoint.cpp b/clang/Analysis/ProgramPoint.cpp deleted file mode 100644 index c089e486988..00000000000 --- a/clang/Analysis/ProgramPoint.cpp +++ /dev/null @@ -1,65 +0,0 @@ -//= ProgramPoint.cpp - Program Points for Path-Sensitive Analysis --*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements methods for subclasses of ProgramPoint. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/CFG.h" -#include "clang/Analysis/ProgramPoint.h" - -using namespace clang; - -BlockEdge::BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2) { - if (B1->succ_size() == 1) { - assert (*(B1->succ_begin()) == B2); - Data = reinterpret_cast(B1) | BlockEdgeSrcKind; - } - else if (B2->pred_size() == 1) { - assert (*(B2->pred_begin()) == B1); - Data = reinterpret_cast(B2) | BlockEdgeDstKind; - } - else - Data = reinterpret_cast(cfg.getBlockEdgeImpl(B1,B2)) - | BlockEdgeAuxKind; -} - -CFGBlock* BlockEdge::getSrc() const { - switch (getKind()) { - default: - assert (false && "Invalid BlockEdgeKind."); - return NULL; - - case BlockEdgeSrcKind: - return reinterpret_cast(getRawPtr()); - - case BlockEdgeDstKind: - return *(reinterpret_cast(getRawPtr())->pred_begin()); - - case BlockEdgeAuxKind: - return reinterpret_cast(getRawPtr())->first; - } -} - -CFGBlock* BlockEdge::getDst() const { - switch (getKind()) { - default: - assert (false && "Invalid BlockEdgeKind."); - return NULL; - - case BlockEdgeSrcKind: - return *(reinterpret_cast(getRawPtr())->succ_begin()); - - case BlockEdgeDstKind: - return reinterpret_cast(getRawPtr()); - - case BlockEdgeAuxKind: - return reinterpret_cast(getRawPtr())->second; - } -} diff --git a/clang/Analysis/RValues.cpp b/clang/Analysis/RValues.cpp deleted file mode 100644 index a4b464949aa..00000000000 --- a/clang/Analysis/RValues.cpp +++ /dev/null @@ -1,389 +0,0 @@ -//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- 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 RVal, LVal, and NonLVal, classes that represent -// abstract r-values for use with path-sensitive value tracking. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/RValues.h" -#include "llvm/Support/Streams.h" - -using namespace clang; -using llvm::dyn_cast; -using llvm::cast; -using llvm::APSInt; - -//===----------------------------------------------------------------------===// -// Symbol Iteration. -//===----------------------------------------------------------------------===// - -RVal::symbol_iterator RVal::symbol_begin() const { - if (isa(this)) - return (symbol_iterator) (&Data); - else if (isa(this)) - return (symbol_iterator) (&Data); - else if (isa(this)) { - const SymIntConstraint& C = - cast(this)->getConstraint(); - - return (symbol_iterator) &C.getSymbol(); - } - - return NULL; -} - -RVal::symbol_iterator RVal::symbol_end() const { - symbol_iterator X = symbol_begin(); - return X ? X+1 : NULL; -} - -//===----------------------------------------------------------------------===// -// Transfer function dispatch for Non-LVals. -//===----------------------------------------------------------------------===// - -RVal -nonlval::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, - const nonlval::ConcreteInt& R) const { - - const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); - - if (X) - return nonlval::ConcreteInt(*X); - else - return UndefinedVal(); -} - - - // Bitwise-Complement. - -nonlval::ConcreteInt -nonlval::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const { - return BasicVals.getValue(~getValue()); -} - - // Unary Minus. - -nonlval::ConcreteInt -nonlval::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const { - assert (U->getType() == U->getSubExpr()->getType()); - assert (U->getType()->isIntegerType()); - return BasicVals.getValue(-getValue()); -} - -//===----------------------------------------------------------------------===// -// Transfer function dispatch for LVals. -//===----------------------------------------------------------------------===// - -RVal -lval::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, - const lval::ConcreteInt& R) const { - - assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub || - (Op >= BinaryOperator::LT && Op <= BinaryOperator::NE)); - - const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); - - if (X) - return lval::ConcreteInt(*X); - else - return UndefinedVal(); -} - -NonLVal LVal::EQ(BasicValueFactory& BasicVals, const LVal& R) const { - - switch (getSubKind()) { - default: - assert(false && "EQ not implemented for this LVal."); - break; - - case lval::ConcreteIntKind: - if (isa(R)) { - bool b = cast(this)->getValue() == - cast(R).getValue(); - - return NonLVal::MakeIntTruthVal(BasicVals, b); - } - else if (isa(R)) { - - const SymIntConstraint& C = - BasicVals.getConstraint(cast(R).getSymbol(), - BinaryOperator::EQ, - cast(this)->getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - break; - - case lval::SymbolValKind: { - if (isa(R)) { - - const SymIntConstraint& C = - BasicVals.getConstraint(cast(this)->getSymbol(), - BinaryOperator::EQ, - cast(R).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - assert (!isa(R) && "FIXME: Implement unification."); - - break; - } - - case lval::DeclValKind: - if (isa(R)) { - bool b = cast(*this) == cast(R); - return NonLVal::MakeIntTruthVal(BasicVals, b); - } - - break; - } - - return NonLVal::MakeIntTruthVal(BasicVals, false); -} - -NonLVal LVal::NE(BasicValueFactory& BasicVals, const LVal& R) const { - switch (getSubKind()) { - default: - assert(false && "NE not implemented for this LVal."); - break; - - case lval::ConcreteIntKind: - if (isa(R)) { - bool b = cast(this)->getValue() != - cast(R).getValue(); - - return NonLVal::MakeIntTruthVal(BasicVals, b); - } - else if (isa(R)) { - - const SymIntConstraint& C = - BasicVals.getConstraint(cast(R).getSymbol(), - BinaryOperator::NE, - cast(this)->getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - break; - - case lval::SymbolValKind: { - if (isa(R)) { - - const SymIntConstraint& C = - BasicVals.getConstraint(cast(this)->getSymbol(), - BinaryOperator::NE, - cast(R).getValue()); - - return nonlval::SymIntConstraintVal(C); - } - - assert (!isa(R) && "FIXME: Implement sym !=."); - - break; - } - - case lval::DeclValKind: - if (isa(R)) { - bool b = cast(*this) == cast(R); - return NonLVal::MakeIntTruthVal(BasicVals, b); - } - - break; - } - - return NonLVal::MakeIntTruthVal(BasicVals, true); -} - -//===----------------------------------------------------------------------===// -// Utility methods for constructing Non-LVals. -//===----------------------------------------------------------------------===// - -NonLVal NonLVal::MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T) { - return nonlval::ConcreteInt(BasicVals.getValue(X, T)); -} - -NonLVal NonLVal::MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I) { - - return nonlval::ConcreteInt(BasicVals.getValue(APSInt(I->getValue(), - I->getType()->isUnsignedIntegerType()))); -} - -NonLVal NonLVal::MakeIntTruthVal(BasicValueFactory& BasicVals, bool b) { - return nonlval::ConcreteInt(BasicVals.getTruthValue(b)); -} - -RVal RVal::GetSymbolValue(SymbolManager& SymMgr, VarDecl* D) { - - QualType T = D->getType(); - - if (T->isPointerType() || T->isReferenceType()) - return lval::SymbolVal(SymMgr.getSymbol(D)); - else - return nonlval::SymbolVal(SymMgr.getSymbol(D)); -} - -//===----------------------------------------------------------------------===// -// Utility methods for constructing LVals. -//===----------------------------------------------------------------------===// - -LVal LVal::MakeVal(AddrLabelExpr* E) { return lval::GotoLabel(E->getLabel()); } - -//===----------------------------------------------------------------------===// -// Utility methods for constructing RVals (both NonLVals and LVals). -//===----------------------------------------------------------------------===// - -RVal RVal::MakeVal(BasicValueFactory& BasicVals, DeclRefExpr* E) { - - ValueDecl* D = cast(E)->getDecl(); - - if (VarDecl* VD = dyn_cast(D)) { - return lval::DeclVal(VD); - } - else if (EnumConstantDecl* ED = dyn_cast(D)) { - - // FIXME: Do we need to cache a copy of this enum, since it - // already has persistent storage? We do this because we - // are comparing states using pointer equality. Perhaps there is - // a better way, since APInts are fairly lightweight. - - return nonlval::ConcreteInt(BasicVals.getValue(ED->getInitVal())); - } - else if (FunctionDecl* FD = dyn_cast(D)) { - return lval::FuncVal(FD); - } - - assert (false && - "ValueDecl support for this ValueDecl not implemented."); - - return UnknownVal(); -} - -//===----------------------------------------------------------------------===// -// Pretty-Printing. -//===----------------------------------------------------------------------===// - -void RVal::printStdErr() const { print(*llvm::cerr.stream()); } - -void RVal::print(std::ostream& Out) const { - - switch (getBaseKind()) { - - case UnknownKind: - Out << "Invalid"; break; - - case NonLValKind: - cast(this)->print(Out); break; - - case LValKind: - cast(this)->print(Out); break; - - case UndefinedKind: - Out << "Undefined"; break; - - default: - assert (false && "Invalid RVal."); - } -} - -static void printOpcode(std::ostream& Out, BinaryOperator::Opcode Op) { - - switch (Op) { - case BinaryOperator::Mul: Out << '*' ; break; - case BinaryOperator::Div: Out << '/' ; break; - case BinaryOperator::Rem: Out << '%' ; break; - case BinaryOperator::Add: Out << '+' ; break; - case BinaryOperator::Sub: Out << '-' ; break; - case BinaryOperator::Shl: Out << "<<" ; break; - case BinaryOperator::Shr: Out << ">>" ; break; - case BinaryOperator::LT: Out << "<" ; break; - case BinaryOperator::GT: Out << '>' ; break; - case BinaryOperator::LE: Out << "<=" ; break; - case BinaryOperator::GE: Out << ">=" ; break; - case BinaryOperator::EQ: Out << "==" ; break; - case BinaryOperator::NE: Out << "!=" ; break; - case BinaryOperator::And: Out << '&' ; break; - case BinaryOperator::Xor: Out << '^' ; break; - case BinaryOperator::Or: Out << '|' ; break; - - default: assert(false && "Not yet implemented."); - } -} - -void NonLVal::print(std::ostream& Out) const { - - switch (getSubKind()) { - - case nonlval::ConcreteIntKind: - Out << cast(this)->getValue().toString(); - - if (cast(this)->getValue().isUnsigned()) - Out << 'U'; - - break; - - case nonlval::SymbolValKind: - Out << '$' << cast(this)->getSymbol(); - break; - - case nonlval::SymIntConstraintValKind: { - const nonlval::SymIntConstraintVal& C = - *cast(this); - - Out << '$' << C.getConstraint().getSymbol() << ' '; - printOpcode(Out, C.getConstraint().getOpcode()); - Out << ' ' << C.getConstraint().getInt().toString(); - - if (C.getConstraint().getInt().isUnsigned()) - Out << 'U'; - - break; - } - - default: - assert (false && "Pretty-printed not implemented for this NonLVal."); - break; - } -} - -void LVal::print(std::ostream& Out) const { - - switch (getSubKind()) { - - case lval::ConcreteIntKind: - Out << cast(this)->getValue().toString() - << " (LVal)"; - break; - - case lval::SymbolValKind: - Out << '$' << cast(this)->getSymbol(); - break; - - case lval::GotoLabelKind: - Out << "&&" - << cast(this)->getLabel()->getID()->getName(); - break; - - case lval::DeclValKind: - Out << '&' - << cast(this)->getDecl()->getIdentifier()->getName(); - break; - - case lval::FuncValKind: - Out << "function " - << cast(this)->getDecl()->getIdentifier()->getName(); - break; - - default: - assert (false && "Pretty-printing not implemented for this LVal."); - break; - } -} diff --git a/clang/Analysis/SymbolManager.cpp b/clang/Analysis/SymbolManager.cpp deleted file mode 100644 index f243fa667b3..00000000000 --- a/clang/Analysis/SymbolManager.cpp +++ /dev/null @@ -1,124 +0,0 @@ -//== SymbolManager.h - Management of Symbolic Values ------------*- 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 SymbolManager, a class that manages symbolic values -// created for use by GRExprEngine and related classes. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/SymbolManager.h" - -using namespace clang; - -SymbolID SymbolManager::getSymbol(VarDecl* D) { - - assert (isa(D) || D->hasGlobalStorage()); - - llvm::FoldingSetNodeID profile; - - ParmVarDecl* PD = dyn_cast(D); - - if (PD) - SymbolDataParmVar::Profile(profile, PD); - else - SymbolDataGlobalVar::Profile(profile, D); - - void* InsertPos; - - SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); - - if (SD) - return SD->getSymbol(); - - if (PD) { - SD = (SymbolData*) BPAlloc.Allocate(); - new (SD) SymbolDataParmVar(SymbolCounter, PD); - } - else { - SD = (SymbolData*) BPAlloc.Allocate(); - new (SD) SymbolDataGlobalVar(SymbolCounter, D); - } - - DataSet.InsertNode(SD, InsertPos); - - DataMap[SymbolCounter] = SD; - return SymbolCounter++; -} - -SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) { - - llvm::FoldingSetNodeID profile; - SymbolDataContentsOf::Profile(profile, sym); - void* InsertPos; - - SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); - - if (SD) - return SD->getSymbol(); - - SD = (SymbolData*) BPAlloc.Allocate(); - new (SD) SymbolDataContentsOf(SymbolCounter, sym); - - - DataSet.InsertNode(SD, InsertPos); - DataMap[SymbolCounter] = SD; - - return SymbolCounter++; -} - -SymbolID SymbolManager::getConjuredSymbol(Expr* E, unsigned Count) { - - llvm::FoldingSetNodeID profile; - SymbolConjured::Profile(profile, E, Count); - void* InsertPos; - - SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); - - if (SD) - return SD->getSymbol(); - - SD = (SymbolData*) BPAlloc.Allocate(); - new (SD) SymbolConjured(SymbolCounter, E, Count); - - DataSet.InsertNode(SD, InsertPos); - DataMap[SymbolCounter] = SD; - - return SymbolCounter++; -} - -const SymbolData& SymbolManager::getSymbolData(SymbolID Sym) const { - DataMapTy::const_iterator I = DataMap.find(Sym); - assert (I != DataMap.end()); - return *I->second; -} - - -QualType SymbolData::getType(const SymbolManager& SymMgr) const { - switch (getKind()) { - default: - assert (false && "getType() not implemented for this symbol."); - - case ParmKind: - return cast(this)->getDecl()->getType(); - - case GlobalKind: - return cast(this)->getDecl()->getType(); - - case ContentsOfKind: { - SymbolID x = cast(this)->getContainerSymbol(); - QualType T = SymMgr.getSymbolData(x).getType(SymMgr); - return T->getAsPointerType()->getPointeeType(); - } - - case ConjuredKind: - return cast(this)->getExpr()->getType(); - } -} - -SymbolManager::~SymbolManager() {} diff --git a/clang/Analysis/UninitializedValues.cpp b/clang/Analysis/UninitializedValues.cpp deleted file mode 100644 index 25a5ecb4837..00000000000 --- a/clang/Analysis/UninitializedValues.cpp +++ /dev/null @@ -1,277 +0,0 @@ -//==- UninitializedValues.cpp - Find Unintialized Values --------*- C++ --*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements Uninitialized Values analysis for source-level CFGs. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/Analyses/UninitializedValues.h" -#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/AST/ASTContext.h" -#include "clang/Analysis/FlowSensitive/DataflowSolver.h" -#include "llvm/Support/Compiler.h" - -#include "llvm/ADT/SmallPtrSet.h" - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Dataflow initialization logic. -//===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN RegisterDecls - : public CFGRecStmtDeclVisitor { - - UninitializedValues::AnalysisDataTy& AD; -public: - RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - - void VisitBlockVarDecl(BlockVarDecl* VD) { AD.Register(VD); } - CFG& getCFG() { return AD.getCFG(); } -}; - -} // end anonymous namespace - -void UninitializedValues::InitializeValues(const CFG& cfg) { - RegisterDecls R(getAnalysisData()); - cfg.VisitBlockStmts(R); -} - -//===----------------------------------------------------------------------===// -// Transfer functions. -//===----------------------------------------------------------------------===// - -namespace { -class VISIBILITY_HIDDEN TransferFuncs - : public CFGStmtVisitor { - - UninitializedValues::ValTy V; - UninitializedValues::AnalysisDataTy& AD; -public: - TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) { - V.resetValues(AD); - } - - UninitializedValues::ValTy& getVal() { return V; } - CFG& getCFG() { return AD.getCFG(); } - - bool VisitDeclRefExpr(DeclRefExpr* DR); - bool VisitBinaryOperator(BinaryOperator* B); - bool VisitUnaryOperator(UnaryOperator* U); - bool VisitStmt(Stmt* S); - bool VisitCallExpr(CallExpr* C); - bool VisitDeclStmt(DeclStmt* D); - bool VisitConditionalOperator(ConditionalOperator* C); - - bool Visit(Stmt *S); - bool BlockStmt_VisitExpr(Expr* E); - - BlockVarDecl* FindBlockVarDecl(Stmt* S); -}; - -static const bool Initialized = true; -static const bool Uninitialized = false; - -bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { - if (BlockVarDecl* VD = dyn_cast(DR->getDecl())) { - if (AD.Observer) AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD); - - // Pseudo-hack to prevent cascade of warnings. If an accessed variable - // is uninitialized, then we are already going to flag a warning for - // this variable, which a "source" of uninitialized values. - // We can otherwise do a full "taint" of uninitialized values. The - // client has both options by toggling AD.FullUninitTaint. - - return AD.FullUninitTaint ? V(VD,AD) : Initialized; - } - else return Initialized; -} - -BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) { - for (;;) - if (ParenExpr* P = dyn_cast(S)) { - S = P->getSubExpr(); continue; - } - else if (DeclRefExpr* DR = dyn_cast(S)) { - if (BlockVarDecl* VD = dyn_cast(DR->getDecl())) - return VD; - else - return NULL; - } - else return NULL; -} - -bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { - if (BlockVarDecl* VD = FindBlockVarDecl(B->getLHS())) - if (B->isAssignmentOp()) { - if (B->getOpcode() == BinaryOperator::Assign) - return V(VD,AD) = Visit(B->getRHS()); - else // Handle +=, -=, *=, etc. We do want '&', not '&&'. - return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS()); - } - - return VisitStmt(B); -} - -bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { - for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator()) - if (BlockVarDecl* VD = dyn_cast(D)) { - if (Stmt* I = VD->getInit()) - V(VD,AD) = AD.FullUninitTaint ? V(cast(I),AD) : Initialized; - else { - // Special case for declarations of array types. For things like: - // - // char x[10]; - // - // we should treat "x" as being initialized, because the variable - // "x" really refers to the memory block. Clearly x[1] is - // uninitialized, but expressions like "(char *) x" really do refer to - // an initialized value. This simple dataflow analysis does not reason - // about the contents of arrays, although it could be potentially - // extended to do so if the array were of constant size. - if (VD->getType()->isArrayType()) - V(VD,AD) = Initialized; - else - V(VD,AD) = Uninitialized; - } - } - - return Uninitialized; // Value is never consumed. -} - -bool TransferFuncs::VisitCallExpr(CallExpr* C) { - VisitChildren(C); - return Initialized; -} - -bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { - switch (U->getOpcode()) { - case UnaryOperator::AddrOf: - if (BlockVarDecl* VD = FindBlockVarDecl(U->getSubExpr())) - return V(VD,AD) = Initialized; - - break; - - case UnaryOperator::SizeOf: - return Initialized; - - default: - break; - } - - return Visit(U->getSubExpr()); -} - -bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) { - Visit(C->getCond()); - - bool rhsResult = Visit(C->getRHS()); - // Handle the GNU extension for missing LHS. - if (Expr *lhs = C->getLHS()) - return Visit(lhs) & rhsResult; // Yes: we want &, not &&. - else - return rhsResult; -} - -bool TransferFuncs::VisitStmt(Stmt* S) { - bool x = Initialized; - - // We don't stop at the first subexpression that is Uninitialized because - // evaluating some subexpressions may result in propogating "Uninitialized" - // or "Initialized" to variables referenced in the other subexpressions. - for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) - if (*I && Visit(*I) == Uninitialized) x = Uninitialized; - - return x; -} - -bool TransferFuncs::Visit(Stmt *S) { - if (AD.isTracked(static_cast(S))) return V(static_cast(S),AD); - else return static_cast*>(this)->Visit(S); -} - -bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { - bool x = static_cast*>(this)->Visit(E); - if (AD.isTracked(E)) V(E,AD) = x; - return x; -} - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Merge operator. -// -// In our transfer functions we take the approach that any -// combination of unintialized values, e.g. Unitialized + ___ = Unitialized. -// -// Merges take the opposite approach. -// -// In the merge of dataflow values we prefer unsoundness, and -// prefer false negatives to false positives. At merges, if a value for a -// tracked Decl is EVER initialized in any of the predecessors we treat it as -// initialized at the confluence point. -//===----------------------------------------------------------------------===// - -namespace { - typedef ExprDeclBitVector_Types::Union Merge; - typedef DataflowSolver Solver; -} - -//===----------------------------------------------------------------------===// -// Unitialized values checker. Scan an AST and flag variable uses -//===----------------------------------------------------------------------===// - -UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} - -namespace { -class VISIBILITY_HIDDEN UninitializedValuesChecker - : public UninitializedValues::ObserverTy { - - ASTContext &Ctx; - Diagnostic &Diags; - llvm::SmallPtrSet AlreadyWarned; - -public: - UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags) - : Ctx(ctx), Diags(diags) {} - - virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V, - UninitializedValues::AnalysisDataTy& AD, - DeclRefExpr* DR, BlockVarDecl* VD) { - - assert ( AD.isTracked(VD) && "Unknown VarDecl."); - - if (V(VD,AD) == Uninitialized) - if (AlreadyWarned.insert(VD)) - Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), - diag::warn_uninit_val); - } -}; -} // end anonymous namespace - -namespace clang { -void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags, - bool FullUninitTaint) { - - // Compute the unitialized values information. - UninitializedValues U(cfg); - U.getAnalysisData().FullUninitTaint = FullUninitTaint; - Solver S(U); - S.runOnCFG(cfg); - - // Scan for DeclRefExprs that use uninitialized values. - UninitializedValuesChecker Observer(Ctx,Diags); - U.getAnalysisData().Observer = &Observer; - S.runOnAllBlocks(cfg); -} -} // end namespace clang diff --git a/clang/Analysis/ValueState.cpp b/clang/Analysis/ValueState.cpp deleted file mode 100644 index c0ed7aa882a..00000000000 --- a/clang/Analysis/ValueState.cpp +++ /dev/null @@ -1,595 +0,0 @@ -//= ValueState*cpp - Path-Sens. "State" for tracking valuues -----*- 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 SymbolID, ExprBindKey, and ValueState* -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/ValueState.h" -#include "llvm/ADT/SmallSet.h" - -using namespace clang; - -bool ValueState::isNotEqual(SymbolID sym, const llvm::APSInt& V) const { - - // Retrieve the NE-set associated with the given symbol. - ConstNotEqTy::TreeTy* T = ConstNotEq.SlimFind(sym); - - // See if V is present in the NE-set. - return T ? T->getValue().second.contains(&V) : false; -} - -const llvm::APSInt* ValueState::getSymVal(SymbolID sym) const { - ConstEqTy::TreeTy* T = ConstEq.SlimFind(sym); - return T ? T->getValue().second : NULL; -} - -ValueState* -ValueStateManager::RemoveDeadBindings(ValueState* St, Stmt* Loc, - const LiveVariables& Liveness) { - - // This code essentially performs a "mark-and-sweep" of the VariableBindings. - // The roots are any Block-level exprs and Decls that our liveness algorithm - // tells us are live. We then see what Decls they may reference, and keep - // those around. This code more than likely can be made faster, and the - // frequency of which this method is called should be experimented with - // for optimum performance. - - llvm::SmallVector WList; - llvm::SmallPtrSet Marked; - llvm::SmallSet MarkedSymbols; - - ValueState NewSt = *St; - - // Drop bindings for subexpressions. - NewSt.SubExprBindings = EXFactory.GetEmptyMap(); - - // Iterate over the block-expr bindings. - - for (ValueState::beb_iterator I = St->beb_begin(), E = St->beb_end(); - I!=E ; ++I) { - Expr* BlkExpr = I.getKey(); - - if (Liveness.isLive(Loc, BlkExpr)) { - RVal X = I.getData(); - - if (isa(X)) { - lval::DeclVal LV = cast(X); - WList.push_back(LV.getDecl()); - } - - for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); - SI != SE; ++SI) { - MarkedSymbols.insert(*SI); - } - } - else { - RVal X = I.getData(); - - if (X.isUndef() && cast(X).getData()) - continue; - - NewSt.BlockExprBindings = Remove(NewSt, BlkExpr); - } - } - - // Iterate over the variable bindings. - - for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I) - if (Liveness.isLive(Loc, I.getKey())) { - WList.push_back(I.getKey()); - - RVal X = I.getData(); - - for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); - SI != SE; ++SI) { - MarkedSymbols.insert(*SI); - } - } - - // Perform the mark-and-sweep. - - while (!WList.empty()) { - - ValueDecl* V = WList.back(); - WList.pop_back(); - - if (Marked.count(V)) - continue; - - Marked.insert(V); - - if (V->getType()->isPointerType()) { - - RVal X = GetRVal(St, lval::DeclVal(cast(V))); - - if (X.isUnknownOrUndef()) - continue; - - LVal LV = cast(X); - - for (RVal::symbol_iterator SI = LV.symbol_begin(), SE = LV.symbol_end(); - SI != SE; ++SI) { - MarkedSymbols.insert(*SI); - } - - if (!isa(LV)) - continue; - - const lval::DeclVal& LVD = cast(LV); - WList.push_back(LVD.getDecl()); - } - } - - // Remove dead variable bindings. - for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I) - if (!Marked.count(I.getKey())) - NewSt.VarBindings = Remove(NewSt, I.getKey()); - - // Remove dead symbols. - for (ValueState::ce_iterator I = St->ce_begin(), E=St->ce_end(); I!=E; ++I) - if (!MarkedSymbols.count(I.getKey())) - NewSt.ConstEq = CEFactory.Remove(NewSt.ConstEq, I.getKey()); - - for (ValueState::cne_iterator I = St->cne_begin(), E=St->cne_end(); I!=E; ++I) - if (!MarkedSymbols.count(I.getKey())) - NewSt.ConstNotEq = CNEFactory.Remove(NewSt.ConstNotEq, I.getKey()); - - return getPersistentState(NewSt); -} - - -RVal ValueStateManager::GetRVal(ValueState* St, LVal LV, QualType T) { - - if (isa(LV)) - return UnknownVal(); - - assert (!isa(LV)); - - switch (LV.getSubKind()) { - case lval::DeclValKind: { - ValueState::VarBindingsTy::TreeTy* T = - St->VarBindings.SlimFind(cast(LV).getDecl()); - - return T ? T->getValue().second : UnknownVal(); - } - - // FIXME: We should limit how far a "ContentsOf" will go... - - case lval::SymbolValKind: { - - - // FIXME: This is a broken representation of memory, and is prone - // to crashing the analyzer when addresses to symbolic values are - // passed through casts. We need a better representation of symbolic - // memory (or just memory in general); probably we should do this - // as a plugin class (similar to GRTransferFuncs). - -#if 0 - const lval::SymbolVal& SV = cast(LV); - assert (T.getTypePtr()); - - // Punt on "symbolic" function pointers. - if (T->isFunctionType()) - return UnknownVal(); - - if (T->isPointerType()) - return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol())); - else - return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol())); -#endif - - return UnknownVal(); - } - - default: - assert (false && "Invalid LVal."); - break; - } - - return UnknownVal(); -} - -ValueState* ValueStateManager::AddNE(ValueState* St, SymbolID sym, - const llvm::APSInt& V) { - - // First, retrieve the NE-set associated with the given symbol. - ValueState::ConstNotEqTy::TreeTy* T = St->ConstNotEq.SlimFind(sym); - ValueState::IntSetTy S = T ? T->getValue().second : ISetFactory.GetEmptySet(); - - // Now add V to the NE set. - S = ISetFactory.Add(S, &V); - - // Create a new state with the old binding replaced. - ValueState NewSt = *St; - NewSt.ConstNotEq = CNEFactory.Add(NewSt.ConstNotEq, sym, S); - - // Get the persistent copy. - return getPersistentState(NewSt); -} - -ValueState* ValueStateManager::AddEQ(ValueState* St, SymbolID sym, - const llvm::APSInt& V) { - - // Create a new state with the old binding replaced. - ValueState NewSt = *St; - NewSt.ConstEq = CEFactory.Add(NewSt.ConstEq, sym, &V); - - // Get the persistent copy. - return getPersistentState(NewSt); -} - -RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) { - - for (;;) { - - switch (E->getStmtClass()) { - - case Stmt::AddrLabelExprClass: - return LVal::MakeVal(cast(E)); - - // ParenExprs are no-ops. - - case Stmt::ParenExprClass: - E = cast(E)->getSubExpr(); - continue; - - // DeclRefExprs can either evaluate to an LVal or a Non-LVal - // (assuming an implicit "load") depending on the context. In this - // context we assume that we are retrieving the value contained - // within the referenced variables. - - case Stmt::DeclRefExprClass: { - - // Check if this expression is a block-level expression. If so, - // return its value. - ValueState::ExprBindingsTy::TreeTy* T=St->BlockExprBindings.SlimFind(E); - if (T) return T->getValue().second; - - RVal X = RVal::MakeVal(BasicVals, cast(E)); - return isa(X) ? GetRVal(St, cast(X)) : X; - } - - case Stmt::CharacterLiteralClass: { - CharacterLiteral* C = cast(E); - return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType()); - } - - case Stmt::IntegerLiteralClass: { - return NonLVal::MakeVal(BasicVals, cast(E)); - } - - // Casts where the source and target type are the same - // are no-ops. We blast through these to get the descendant - // subexpression that has a value. - - case Stmt::ImplicitCastExprClass: { - ImplicitCastExpr* C = cast(E); - QualType CT = C->getType(); - - if (CT->isVoidType()) - return UnknownVal(); - - QualType ST = C->getSubExpr()->getType(); - - if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { - E = C->getSubExpr(); - continue; - } - - break; - } - - case Stmt::CastExprClass: { - CastExpr* C = cast(E); - QualType CT = C->getType(); - QualType ST = C->getSubExpr()->getType(); - - if (CT->isVoidType()) - return UnknownVal(); - - if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { - E = C->getSubExpr(); - continue; - } - - break; - } - - case Stmt::UnaryOperatorClass: { - - UnaryOperator* U = cast(E); - - if (U->getOpcode() == UnaryOperator::Plus) { - E = U->getSubExpr(); - continue; - } - - break; - } - - // Handle all other Expr* using a lookup. - - default: - break; - }; - - break; - } - - ValueState::ExprBindingsTy::TreeTy* T = St->SubExprBindings.SlimFind(E); - - if (T) - return T->getValue().second; - - T = St->BlockExprBindings.SlimFind(E); - return T ? T->getValue().second : UnknownVal(); -} - -RVal ValueStateManager::GetBlkExprRVal(ValueState* St, Expr* E) { - - E = E->IgnoreParens(); - - switch (E->getStmtClass()) { - case Stmt::CharacterLiteralClass: { - CharacterLiteral* C = cast(E); - return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType()); - } - - case Stmt::IntegerLiteralClass: { - return NonLVal::MakeVal(BasicVals, cast(E)); - } - - default: { - ValueState::ExprBindingsTy::TreeTy* T = St->BlockExprBindings.SlimFind(E); - return T ? T->getValue().second : UnknownVal(); - } - } -} - -RVal ValueStateManager::GetLVal(ValueState* St, Expr* E) { - - E = E->IgnoreParens(); - - if (DeclRefExpr* DR = dyn_cast(E)) { - ValueDecl* VD = DR->getDecl(); - - if (FunctionDecl* FD = dyn_cast(VD)) - return lval::FuncVal(FD); - else - return lval::DeclVal(cast(DR->getDecl())); - } - - if (UnaryOperator* U = dyn_cast(E)) - if (U->getOpcode() == UnaryOperator::Deref) { - E = U->getSubExpr()->IgnoreParens(); - - if (DeclRefExpr* DR = dyn_cast(E)) { - lval::DeclVal X(cast(DR->getDecl())); - return GetRVal(St, X); - } - else - return GetRVal(St, E); - } - - return GetRVal(St, E); -} - -ValueState* -ValueStateManager::SetRVal(ValueState* St, Expr* E, RVal V, - bool isBlkExpr, bool Invalidate) { - - assert (E); - - if (V.isUnknown()) { - - if (Invalidate) { - - ValueState NewSt = *St; - - if (isBlkExpr) - NewSt.BlockExprBindings = EXFactory.Remove(NewSt.BlockExprBindings, E); - else - NewSt.SubExprBindings = EXFactory.Remove(NewSt.SubExprBindings, E); - - return getPersistentState(NewSt); - } - - return St; - } - - ValueState NewSt = *St; - - if (isBlkExpr) { - NewSt.BlockExprBindings = EXFactory.Add(NewSt.BlockExprBindings, E, V); - } - else { - NewSt.SubExprBindings = EXFactory.Add(NewSt.SubExprBindings, E, V); - } - - return getPersistentState(NewSt); -} - - -ValueState* ValueStateManager::SetRVal(ValueState* St, LVal LV, RVal V) { - - switch (LV.getSubKind()) { - - case lval::DeclValKind: - return V.isUnknown() - ? UnbindVar(St, cast(LV).getDecl()) - : BindVar(St, cast(LV).getDecl(), V); - - default: - assert ("SetRVal for given LVal type not yet implemented."); - return St; - } -} - -void ValueStateManager::BindVar(ValueState& StImpl, VarDecl* D, RVal V) { - StImpl.VarBindings = VBFactory.Add(StImpl.VarBindings, D, V); -} - -ValueState* ValueStateManager::BindVar(ValueState* St, VarDecl* D, RVal V) { - - // Create a new state with the old binding removed. - ValueState NewSt = *St; - NewSt.VarBindings = VBFactory.Add(NewSt.VarBindings, D, V); - - // Get the persistent copy. - return getPersistentState(NewSt); -} - -ValueState* ValueStateManager::UnbindVar(ValueState* St, VarDecl* D) { - - // Create a new state with the old binding removed. - ValueState NewSt = *St; - NewSt.VarBindings = VBFactory.Remove(NewSt.VarBindings, D); - - // Get the persistent copy. - return getPersistentState(NewSt); -} - -void ValueStateManager::Unbind(ValueState& StImpl, LVal LV) { - - if (isa(LV)) - StImpl.VarBindings = VBFactory.Remove(StImpl.VarBindings, - cast(LV).getDecl()); - -} - -ValueState* ValueStateManager::getInitialState() { - - // Create a state with empty variable bindings. - ValueState StateImpl(EXFactory.GetEmptyMap(), - VBFactory.GetEmptyMap(), - CNEFactory.GetEmptyMap(), - CEFactory.GetEmptyMap()); - - return getPersistentState(StateImpl); -} - -ValueState* ValueStateManager::getPersistentState(ValueState& State) { - - llvm::FoldingSetNodeID ID; - State.Profile(ID); - void* InsertPos; - - if (ValueState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) - return I; - - ValueState* I = (ValueState*) Alloc.Allocate(); - new (I) ValueState(State); - StateSet.InsertNode(I, InsertPos); - return I; -} - -void ValueState::printDOT(std::ostream& Out, CheckerStatePrinter* P) const { - print(Out, P, "\\l", "\\|"); -} - -void ValueState::printStdErr(CheckerStatePrinter* P) const { - print(*llvm::cerr, P); -} - -void ValueState::print(std::ostream& Out, CheckerStatePrinter* P, - const char* nl, const char* sep) const { - - // Print Variable Bindings - Out << "Variables:" << nl; - - bool isFirst = true; - - for (vb_iterator I = vb_begin(), E = vb_end(); I != E; ++I) { - - if (isFirst) isFirst = false; - else Out << nl; - - Out << ' ' << I.getKey()->getName() << " : "; - I.getData().print(Out); - } - - // Print Subexpression bindings. - - isFirst = true; - - for (seb_iterator I = seb_begin(), E = seb_end(); I != E; ++I) { - - if (isFirst) { - Out << nl << nl << "Sub-Expressions:" << nl; - isFirst = false; - } - else { Out << nl; } - - Out << " (" << (void*) I.getKey() << ") "; - I.getKey()->printPretty(Out); - Out << " : "; - I.getData().print(Out); - } - - // Print block-expression bindings. - - isFirst = true; - - for (beb_iterator I = beb_begin(), E = beb_end(); I != E; ++I) { - - if (isFirst) { - Out << nl << nl << "Block-level Expressions:" << nl; - isFirst = false; - } - else { Out << nl; } - - Out << " (" << (void*) I.getKey() << ") "; - I.getKey()->printPretty(Out); - Out << " : "; - I.getData().print(Out); - } - - // Print equality constraints. - - if (!ConstEq.isEmpty()) { - - Out << nl << sep << "'==' constraints:"; - - for (ConstEqTy::iterator I = ConstEq.begin(), - E = ConstEq.end(); I!=E; ++I) { - - Out << nl << " $" << I.getKey() - << " : " << I.getData()->toString(); - } - } - - // Print != constraints. - - if (!ConstNotEq.isEmpty()) { - - Out << nl << sep << "'!=' constraints:"; - - for (ConstNotEqTy::iterator I = ConstNotEq.begin(), - EI = ConstNotEq.end(); I != EI; ++I) { - - Out << nl << " $" << I.getKey() << " : "; - isFirst = true; - - IntSetTy::iterator J = I.getData().begin(), EJ = I.getData().end(); - - for ( ; J != EJ; ++J) { - if (isFirst) isFirst = false; - else Out << ", "; - - Out << (*J)->toString(); - } - } - } - - // Print checker-specific data. - - if (P && CheckerState) - P->PrintCheckerState(Out, CheckerState, nl, sep); -} diff --git a/clang/Basic/Diagnostic.cpp b/clang/Basic/Diagnostic.cpp deleted file mode 100644 index f62b8f126cd..00000000000 --- a/clang/Basic/Diagnostic.cpp +++ /dev/null @@ -1,232 +0,0 @@ -//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Diagnostic-related interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceLocation.h" -#include -#include -#include -#include -using namespace clang; - -//===----------------------------------------------------------------------===// -// Builtin Diagnostic information -//===----------------------------------------------------------------------===// - -/// Flag values for diagnostics. -enum { - // Diagnostic classes. - NOTE = 0x01, - WARNING = 0x02, - EXTENSION = 0x03, - ERROR = 0x04, - class_mask = 0x07 -}; - -/// DiagnosticFlags - A set of flags, or'd together, that describe the -/// diagnostic. -static unsigned char DiagnosticFlags[] = { -#define DIAG(ENUM,FLAGS,DESC) FLAGS, -#include "clang/Basic/DiagnosticKinds.def" - 0 -}; - -/// getDiagClass - Return the class field of the diagnostic. -/// -static unsigned getBuiltinDiagClass(unsigned DiagID) { - assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && - "Diagnostic ID out of range!"); - return DiagnosticFlags[DiagID] & class_mask; -} - -/// DiagnosticText - An english message to print for the diagnostic. These -/// should be localized. -static const char * const DiagnosticText[] = { -#define DIAG(ENUM,FLAGS,DESC) DESC, -#include "clang/Basic/DiagnosticKinds.def" - 0 -}; - -//===----------------------------------------------------------------------===// -// Custom Diagnostic information -//===----------------------------------------------------------------------===// - -namespace clang { - namespace diag { - class CustomDiagInfo { - typedef std::pair DiagDesc; - std::vector DiagInfo; - std::map DiagIDs; - public: - - /// getDescription - Return the description of the specified custom - /// diagnostic. - const char *getDescription(unsigned DiagID) const { - assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && - "Invalid diagnosic ID"); - return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str(); - } - - /// getLevel - Return the level of the specified custom diagnostic. - Diagnostic::Level getLevel(unsigned DiagID) const { - assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && - "Invalid diagnosic ID"); - return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first; - } - - unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) { - DiagDesc D(L, Message); - // Check to see if it already exists. - std::map::iterator I = DiagIDs.lower_bound(D); - if (I != DiagIDs.end() && I->first == D) - return I->second; - - // If not, assign a new ID. - unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS; - DiagIDs.insert(std::make_pair(D, ID)); - DiagInfo.push_back(D); - return ID; - } - }; - - } // end diag namespace -} // end clang namespace - - -//===----------------------------------------------------------------------===// -// Common Diagnostic implementation -//===----------------------------------------------------------------------===// - -Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { - WarningsAsErrors = false; - WarnOnExtensions = false; - ErrorOnExtensions = false; - // Clear all mappings, setting them to MAP_DEFAULT. - memset(DiagMappings, 0, sizeof(DiagMappings)); - - ErrorOccurred = false; - NumDiagnostics = 0; - NumErrors = 0; - CustomDiagInfo = 0; -} - -Diagnostic::~Diagnostic() { - delete CustomDiagInfo; -} - -/// getCustomDiagID - Return an ID for a diagnostic with the specified message -/// and level. If this is the first request for this diagnosic, it is -/// registered and created, otherwise the existing ID is returned. -unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { - if (CustomDiagInfo == 0) - CustomDiagInfo = new diag::CustomDiagInfo(); - return CustomDiagInfo->getOrCreateDiagID(L, Message); -} - - -/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic -/// level of the specified diagnostic ID is a Note, Warning, or Extension. -/// Note that this only works on builtin diagnostics, not custom ones. -bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { - return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && - getBuiltinDiagClass(DiagID) < ERROR; -} - - -/// getDescription - Given a diagnostic ID, return a description of the -/// issue. -const char *Diagnostic::getDescription(unsigned DiagID) { - if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) - return DiagnosticText[DiagID]; - else - return CustomDiagInfo->getDescription(DiagID); -} - -/// getDiagnosticLevel - Based on the way the client configured the Diagnostic -/// object, classify the specified diagnostic ID into a Level, consumable by -/// the DiagnosticClient. -Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { - // Handle custom diagnostics, which cannot be mapped. - if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) - return CustomDiagInfo->getLevel(DiagID); - - unsigned DiagClass = getBuiltinDiagClass(DiagID); - - // Specific non-error diagnostics may be mapped to various levels from ignored - // to error. - if (DiagClass < ERROR) { - switch (getDiagnosticMapping((diag::kind)DiagID)) { - case diag::MAP_DEFAULT: break; - case diag::MAP_IGNORE: return Ignored; - case diag::MAP_WARNING: DiagClass = WARNING; break; - case diag::MAP_ERROR: DiagClass = ERROR; break; - } - } - - // Map diagnostic classes based on command line argument settings. - if (DiagClass == EXTENSION) { - if (ErrorOnExtensions) - DiagClass = ERROR; - else if (WarnOnExtensions) - DiagClass = WARNING; - else - return Ignored; - } - - // If warnings are to be treated as errors, indicate this as such. - if (DiagClass == WARNING && WarningsAsErrors) - DiagClass = ERROR; - - switch (DiagClass) { - default: assert(0 && "Unknown diagnostic class!"); - case NOTE: return Diagnostic::Note; - case WARNING: return Diagnostic::Warning; - case ERROR: return Diagnostic::Error; - } -} - -/// Report - Issue the message to the client. If the client wants us to stop -/// compilation, return true, otherwise return false. DiagID is a member of -/// the diag::kind enum. -void Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID, - const std::string *Strs, unsigned NumStrs, - const SourceRange *Ranges, unsigned NumRanges) { - - // Figure out the diagnostic level of this message. - Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID); - - // If the client doesn't care about this message, don't issue it. - if (DiagLevel == Diagnostic::Ignored) - return; - - // If this is not an error and we are in a system header, ignore it. We have - // to check on the original class here, because we also want to ignore - // extensions and warnings in -Werror and -pedantic-errors modes, which *map* - // warnings/extensions to errors. - if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && - getBuiltinDiagClass(DiagID) != ERROR && - Client.isInSystemHeader(Pos)) - return; - - if (DiagLevel >= Diagnostic::Error) { - ErrorOccurred = true; - ++NumErrors; - } - - // Finally, report it. - Client.HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID, - Strs, NumStrs, Ranges, NumRanges); - ++NumDiagnostics; -} - -DiagnosticClient::~DiagnosticClient() {} diff --git a/clang/Basic/FileManager.cpp b/clang/Basic/FileManager.cpp deleted file mode 100644 index cfc08ed084b..00000000000 --- a/clang/Basic/FileManager.cpp +++ /dev/null @@ -1,275 +0,0 @@ -///===--- FileManager.cpp - File System Probing and Caching ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the FileManager interface. -// -//===----------------------------------------------------------------------===// -// -// TODO: This should index all interesting directories with dirent calls. -// getdirentries ? -// opendir/readdir_r/closedir ? -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/FileManager.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" -#include "llvm/Support/Streams.h" -#include "llvm/Config/config.h" -using namespace clang; - -// FIXME: Enhance libsystem to support inode and other fields. -#include - -#if defined(_MSC_VER) -#define S_ISDIR(s) (_S_IFDIR & s) -#endif - -/// NON_EXISTENT_DIR - A special value distinct from null that is used to -/// represent a dir name that doesn't exist on the disk. -#define NON_EXISTENT_DIR reinterpret_cast((intptr_t)-1) - -#ifdef LLVM_ON_WIN32 - -#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\') - -namespace { - static std::string GetFullPath(const char *relPath) - { - char *absPathStrPtr = _fullpath(NULL, relPath, 0); - assert(absPathStrPtr && "_fullpath() returned NULL!"); - - std::string absPath(absPathStrPtr); - - free(absPathStrPtr); - return absPath; - } -} - -class FileManager::UniqueDirContainer { - /// UniqueDirs - Cache from full path to existing directories/files. - /// - llvm::StringMap UniqueDirs; - -public: - DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { - std::string FullPath(GetFullPath(Name)); - return UniqueDirs.GetOrCreateValue( - FullPath.c_str(), - FullPath.c_str() + FullPath.size() - ).getValue(); - } - - size_t size() { return UniqueDirs.size(); } -}; - -class FileManager::UniqueFileContainer { - /// UniqueFiles - Cache from full path to existing directories/files. - /// - llvm::StringMap UniqueFiles; - -public: - FileEntry &getFile(const char *Name, struct stat &StatBuf) { - std::string FullPath(GetFullPath(Name)); - return UniqueFiles.GetOrCreateValue( - FullPath.c_str(), - FullPath.c_str() + FullPath.size() - ).getValue(); - } - - size_t size() { return UniqueFiles.size(); } -}; - -#else - -#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/') - -class FileManager::UniqueDirContainer { - /// UniqueDirs - Cache from ID's to existing directories/files. - /// - std::map, DirectoryEntry> UniqueDirs; - -public: - DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { - return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; - } - - size_t size() { return UniqueDirs.size(); } -}; - -class FileManager::UniqueFileContainer { - /// UniqueFiles - Cache from ID's to existing directories/files. - /// - std::set UniqueFiles; - -public: - FileEntry &getFile(const char *Name, struct stat &StatBuf) { - return - const_cast( - *UniqueFiles.insert(FileEntry(StatBuf.st_dev, - StatBuf.st_ino)).first); - } - - size_t size() { return UniqueFiles.size(); } -}; - -#endif - - -FileManager::FileManager() : UniqueDirs(*new UniqueDirContainer), - UniqueFiles(*new UniqueFileContainer), - DirEntries(64), FileEntries(64), NextFileUID(0) -{ - NumDirLookups = NumFileLookups = 0; - NumDirCacheMisses = NumFileCacheMisses = 0; -} - -FileManager::~FileManager() { - delete &UniqueDirs; - delete &UniqueFiles; -} - - -/// getDirectory - Lookup, cache, and verify the specified directory. This -/// returns null if the directory doesn't exist. -/// -const DirectoryEntry *FileManager::getDirectory(const char *NameStart, - const char *NameEnd) { - ++NumDirLookups; - llvm::StringMapEntry &NamedDirEnt = - DirEntries.GetOrCreateValue(NameStart, NameEnd); - - // See if there is already an entry in the map. - if (NamedDirEnt.getValue()) - return NamedDirEnt.getValue() == NON_EXISTENT_DIR - ? 0 : NamedDirEnt.getValue(); - - ++NumDirCacheMisses; - - // By default, initialize it to invalid. - NamedDirEnt.setValue(NON_EXISTENT_DIR); - - // Get the null-terminated directory name as stored as the key of the - // DirEntries map. - const char *InterndDirName = NamedDirEnt.getKeyData(); - - // Check to see if the directory exists. - struct stat StatBuf; - if (stat(InterndDirName, &StatBuf) || // Error stat'ing. - !S_ISDIR(StatBuf.st_mode)) // Not a directory? - return 0; - - // It exists. See if we have already opened a directory with the same inode. - // This occurs when one dir is symlinked to another, for example. - DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); - - NamedDirEnt.setValue(&UDE); - if (UDE.getName()) // Already have an entry with this inode, return it. - return &UDE; - - // Otherwise, we don't have this directory yet, add it. We use the string - // key from the DirEntries map as the string. - UDE.Name = InterndDirName; - return &UDE; -} - -/// NON_EXISTENT_FILE - A special value distinct from null that is used to -/// represent a filename that doesn't exist on the disk. -#define NON_EXISTENT_FILE reinterpret_cast((intptr_t)-1) - -/// getFile - Lookup, cache, and verify the specified file. This returns null -/// if the file doesn't exist. -/// -const FileEntry *FileManager::getFile(const char *NameStart, - const char *NameEnd) { - ++NumFileLookups; - - // See if there is already an entry in the map. - llvm::StringMapEntry &NamedFileEnt = - FileEntries.GetOrCreateValue(NameStart, NameEnd); - - // See if there is already an entry in the map. - if (NamedFileEnt.getValue()) - return NamedFileEnt.getValue() == NON_EXISTENT_FILE - ? 0 : NamedFileEnt.getValue(); - - ++NumFileCacheMisses; - - // By default, initialize it to invalid. - NamedFileEnt.setValue(NON_EXISTENT_FILE); - - // Figure out what directory it is in. If the string contains a / in it, - // strip off everything after it. - // FIXME: this logic should be in sys::Path. - const char *SlashPos = NameEnd-1; - while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) - --SlashPos; - - const DirectoryEntry *DirInfo; - if (SlashPos < NameStart) { - // Use the current directory if file has no path component. - const char *Name = "."; - DirInfo = getDirectory(Name, Name+1); - } else if (SlashPos == NameEnd-1) - return 0; // If filename ends with a /, it's a directory. - else - DirInfo = getDirectory(NameStart, SlashPos); - - if (DirInfo == 0) // Directory doesn't exist, file can't exist. - return 0; - - // Get the null-terminated file name as stored as the key of the - // FileEntries map. - const char *InterndFileName = NamedFileEnt.getKeyData(); - - // FIXME: Use the directory info to prune this, before doing the stat syscall. - // FIXME: This will reduce the # syscalls. - - // Nope, there isn't. Check to see if the file exists. - struct stat StatBuf; - //llvm::cerr << "STATING: " << Filename; - if (stat(InterndFileName, &StatBuf) || // Error stat'ing. - S_ISDIR(StatBuf.st_mode)) { // A directory? - // If this file doesn't exist, we leave a null in FileEntries for this path. - //llvm::cerr << ": Not existing\n"; - return 0; - } - //llvm::cerr << ": exists\n"; - - // It exists. See if we have already opened a file with the same inode. - // This occurs when one dir is symlinked to another, for example. - FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); - - NamedFileEnt.setValue(&UFE); - if (UFE.getName()) // Already have an entry with this inode, return it. - return &UFE; - - // Otherwise, we don't have this directory yet, add it. - // FIXME: Change the name to be a char* that points back to the 'FileEntries' - // key. - UFE.Name = InterndFileName; - UFE.Size = StatBuf.st_size; - UFE.ModTime = StatBuf.st_mtime; - UFE.Dir = DirInfo; - UFE.UID = NextFileUID++; - return &UFE; -} - -void FileManager::PrintStats() const { - llvm::cerr << "\n*** File Manager Stats:\n"; - llvm::cerr << UniqueFiles.size() << " files found, " - << UniqueDirs.size() << " dirs found.\n"; - llvm::cerr << NumDirLookups << " dir lookups, " - << NumDirCacheMisses << " dir cache misses.\n"; - llvm::cerr << NumFileLookups << " file lookups, " - << NumFileCacheMisses << " file cache misses.\n"; - - //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups; -} diff --git a/clang/Basic/IdentifierTable.cpp b/clang/Basic/IdentifierTable.cpp deleted file mode 100644 index 65e984a0f78..00000000000 --- a/clang/Basic/IdentifierTable.cpp +++ /dev/null @@ -1,551 +0,0 @@ -//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the IdentifierInfo, IdentifierVisitor, and -// IdentifierTable interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/IdentifierTable.h" -#include "clang/Basic/LangOptions.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using namespace clang; - -//===----------------------------------------------------------------------===// -// IdentifierInfo Implementation -//===----------------------------------------------------------------------===// - -IdentifierInfo::IdentifierInfo() { - TokenID = tok::identifier; - ObjCID = tok::objc_not_keyword; - BuiltinID = 0; - HasMacro = false; - IsExtension = false; - IsPoisoned = false; - IsCPPOperatorKeyword = false; - FETokenInfo = 0; -} - -//===----------------------------------------------------------------------===// -// IdentifierTable Implementation -//===----------------------------------------------------------------------===// - -IdentifierTable::IdentifierTable(const LangOptions &LangOpts) - // Start with space for 8K identifiers. - : HashTable(8192) { - - // Populate the identifier table with info about keywords for the current - // language. - AddKeywords(LangOpts); -} - -// This cstor is intended to be used only for serialization. -IdentifierTable::IdentifierTable() : HashTable(8192) {} - -//===----------------------------------------------------------------------===// -// Language Keyword Implementation -//===----------------------------------------------------------------------===// - -/// AddKeyword - This method is used to associate a token ID with specific -/// 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 -/// 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 -/// specified language. -static void AddKeyword(const char *Keyword, unsigned KWLen, - tok::TokenKind TokenCode, - int C90, int C99, int CXX, int CXX0x, int BoolSupport, - const LangOptions &LangOpts, IdentifierTable &Table) { - int Flags = 0; - if (BoolSupport != 0) { - Flags = LangOpts.Boolean ? BoolSupport : 2; - } else if (LangOpts.CPlusPlus) { - Flags = LangOpts.CPlusPlus0x ? CXX0x : CXX; - } else if (LangOpts.C99) { - Flags = C99; - } else { - Flags = C90; - } - - // Don't add this keyword if disabled in this language or if an extension - // and extensions are disabled. - if (Flags + LangOpts.NoExtensions >= 2) return; - - IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen); - Info.setTokenID(TokenCode); - Info.setIsExtensionToken(Flags == 1); -} - -static void AddAlias(const char *Keyword, unsigned KWLen, - tok::TokenKind AliaseeID, - const char *AliaseeKeyword, unsigned AliaseeKWLen, - const LangOptions &LangOpts, IdentifierTable &Table) { - IdentifierInfo &AliasInfo = Table.get(Keyword, Keyword+KWLen); - IdentifierInfo &AliaseeInfo = Table.get(AliaseeKeyword, - AliaseeKeyword+AliaseeKWLen); - AliasInfo.setTokenID(AliaseeID); - AliasInfo.setIsExtensionToken(AliaseeInfo.isExtensionToken()); -} - -/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative -/// representations. -static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, - tok::TokenKind TokenCode, - IdentifierTable &Table) { - IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); - Info.setTokenID(TokenCode); - Info.setIsCPlusPlusOperatorKeyword(); -} - -/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or -/// "property". -static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, - const char *Name, unsigned NameLen, - IdentifierTable &Table) { - Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID); -} - -/// AddKeywords - Add all keywords to the symbol table. -/// -void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { - enum { - C90Shift = 0, - EXTC90 = 1 << C90Shift, - NOTC90 = 2 << C90Shift, - C99Shift = 2, - EXTC99 = 1 << C99Shift, - NOTC99 = 2 << C99Shift, - CPPShift = 4, - EXTCPP = 1 << CPPShift, - NOTCPP = 2 << CPPShift, - CPP0xShift = 6, - EXTCPP0x = 1 << CPP0xShift, - NOTCPP0x = 2 << CPP0xShift, - BoolShift = 8, - BOOLSUPPORT = 1 << BoolShift, - Mask = 3 - }; - - // Add keywords and tokens for the current language. -#define KEYWORD(NAME, FLAGS) \ - AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \ - ((FLAGS) >> C90Shift) & Mask, \ - ((FLAGS) >> C99Shift) & Mask, \ - ((FLAGS) >> CPPShift) & Mask, \ - ((FLAGS) >> CPP0xShift) & Mask, \ - ((FLAGS) >> BoolShift) & Mask, LangOpts, *this); -#define ALIAS(NAME, TOK) \ - AddAlias(NAME, strlen(NAME), tok::kw_ ## TOK, #TOK, strlen(#TOK), \ - LangOpts, *this); -#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ - if (LangOpts.CXXOperatorNames) \ - AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this); -#define OBJC1_AT_KEYWORD(NAME) \ - if (LangOpts.ObjC1) \ - AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); -#define OBJC2_AT_KEYWORD(NAME) \ - if (LangOpts.ObjC2) \ - AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); -#include "clang/Basic/TokenKinds.def" -} - -tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { - // We use a perfect hash function here involving the length of the keyword, - // the first and third character. For preprocessor ID's there are no - // collisions (if there were, the switch below would complain about duplicate - // case values). Note that this depends on 'if' being null terminated. - -#define HASH(LEN, FIRST, THIRD) \ - (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) -#define CASE(LEN, FIRST, THIRD, NAME) \ - case HASH(LEN, FIRST, THIRD): \ - return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME - - unsigned Len = getLength(); - if (Len < 2) return tok::pp_not_keyword; - const char *Name = getName(); - switch (HASH(Len, Name[0], Name[2])) { - default: return tok::pp_not_keyword; - CASE( 2, 'i', '\0', if); - CASE( 4, 'e', 'i', elif); - CASE( 4, 'e', 's', else); - CASE( 4, 'l', 'n', line); - CASE( 4, 's', 'c', sccs); - CASE( 5, 'e', 'd', endif); - CASE( 5, 'e', 'r', error); - CASE( 5, 'i', 'e', ident); - CASE( 5, 'i', 'd', ifdef); - CASE( 5, 'u', 'd', undef); - - CASE( 6, 'a', 's', assert); - CASE( 6, 'd', 'f', define); - CASE( 6, 'i', 'n', ifndef); - CASE( 6, 'i', 'p', import); - CASE( 6, 'p', 'a', pragma); - - CASE( 7, 'd', 'f', defined); - CASE( 7, 'i', 'c', include); - CASE( 7, 'w', 'r', warning); - - CASE( 8, 'u', 'a', unassert); - CASE(12, 'i', 'c', include_next); -#undef CASE -#undef HASH - } -} - -//===----------------------------------------------------------------------===// -// Stats Implementation -//===----------------------------------------------------------------------===// - -/// PrintStats - Print statistics about how well the identifier table is doing -/// at hashing identifiers. -void IdentifierTable::PrintStats() const { - unsigned NumBuckets = HashTable.getNumBuckets(); - unsigned NumIdentifiers = HashTable.getNumItems(); - unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers; - unsigned AverageIdentifierSize = 0; - unsigned MaxIdentifierLength = 0; - - // TODO: Figure out maximum times an identifier had to probe for -stats. - for (llvm::StringMap::const_iterator - I = HashTable.begin(), E = HashTable.end(); I != E; ++I) { - unsigned IdLen = I->getKeyLength(); - AverageIdentifierSize += IdLen; - if (MaxIdentifierLength < IdLen) - MaxIdentifierLength = IdLen; - } - - fprintf(stderr, "\n*** Identifier Table Stats:\n"); - fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers); - fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets); - fprintf(stderr, "Hash density (#identifiers per bucket): %f\n", - NumIdentifiers/(double)NumBuckets); - fprintf(stderr, "Ave identifier length: %f\n", - (AverageIdentifierSize/(double)NumIdentifiers)); - fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength); - - // Compute statistics about the memory allocated for identifiers. - HashTable.getAllocator().PrintStats(); -} - -//===----------------------------------------------------------------------===// -// SelectorTable Implementation -//===----------------------------------------------------------------------===// - -unsigned llvm::DenseMapInfo::getHashValue(clang::Selector S) { - return DenseMapInfo::getHashValue(S.getAsOpaquePtr()); -} - - -/// MultiKeywordSelector - One of these variable length records is kept for each -/// selector containing more than one keyword. We use a folding set -/// to unique aggregate names (keyword selectors in ObjC parlance). Access to -/// this class is provided strictly through Selector. -namespace clang { -class MultiKeywordSelector : public llvm::FoldingSetNode { - friend SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer&); - MultiKeywordSelector(unsigned nKeys) : NumArgs(nKeys) {} -public: - unsigned NumArgs; - - // Constructor for keyword selectors. - MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { - assert((nKeys > 1) && "not a multi-keyword selector"); - NumArgs = nKeys; - - // Fill in the trailing keyword array. - IdentifierInfo **KeyInfo = reinterpret_cast(this+1); - for (unsigned i = 0; i != nKeys; ++i) - KeyInfo[i] = IIV[i]; - } - - // getName - Derive the full selector name and return it. - std::string getName() const; - - unsigned getNumArgs() const { return NumArgs; } - - typedef IdentifierInfo *const *keyword_iterator; - keyword_iterator keyword_begin() const { - return reinterpret_cast(this+1); - } - keyword_iterator keyword_end() const { - return keyword_begin()+NumArgs; - } - IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { - assert(i < NumArgs && "getIdentifierInfoForSlot(): illegal index"); - return keyword_begin()[i]; - } - static void Profile(llvm::FoldingSetNodeID &ID, - keyword_iterator ArgTys, unsigned NumArgs) { - ID.AddInteger(NumArgs); - for (unsigned i = 0; i != NumArgs; ++i) - ID.AddPointer(ArgTys[i]); - } - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, keyword_begin(), NumArgs); - } -}; -} // end namespace clang. - -unsigned Selector::getNumArgs() const { - unsigned IIF = getIdentifierInfoFlag(); - if (IIF == ZeroArg) - return 0; - if (IIF == OneArg) - return 1; - // We point to a MultiKeywordSelector (pointer doesn't contain any flags). - MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); - return SI->getNumArgs(); -} - -IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { - if (IdentifierInfo *II = getAsIdentifierInfo()) { - assert(argIndex == 0 && "illegal keyword index"); - return II; - } - // We point to a MultiKeywordSelector (pointer doesn't contain any flags). - MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); - return SI->getIdentifierInfoForSlot(argIndex); -} - -std::string MultiKeywordSelector::getName() const { - std::string Result; - unsigned Length = 0; - for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { - if (*I) - Length += (*I)->getLength(); - ++Length; // : - } - - Result.reserve(Length); - - for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { - if (*I) - Result.insert(Result.end(), (*I)->getName(), - (*I)->getName()+(*I)->getLength()); - Result.push_back(':'); - } - - return Result; -} - -std::string Selector::getName() const { - if (IdentifierInfo *II = getAsIdentifierInfo()) { - if (getNumArgs() == 0) - return II->getName(); - - std::string Res = II->getName(); - Res += ":"; - return Res; - } - - // We have a multiple keyword selector (no embedded flags). - return reinterpret_cast(InfoPtr)->getName(); -} - - -Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { - if (nKeys < 2) - return Selector(IIV[0], nKeys); - - llvm::FoldingSet *SelTab; - - SelTab = static_cast *>(Impl); - - // Unique selector, to guarantee there is one per name. - llvm::FoldingSetNodeID ID; - MultiKeywordSelector::Profile(ID, IIV, nKeys); - - void *InsertPos = 0; - if (MultiKeywordSelector *SI = SelTab->FindNodeOrInsertPos(ID, InsertPos)) - return Selector(SI); - - // MultiKeywordSelector objects are not allocated with new because they have a - // variable size array (for parameter types) at the end of them. - MultiKeywordSelector *SI = - (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + - nKeys*sizeof(IdentifierInfo *)); - new (SI) MultiKeywordSelector(nKeys, IIV); - SelTab->InsertNode(SI, InsertPos); - return Selector(SI); -} - -SelectorTable::SelectorTable() { - Impl = new llvm::FoldingSet; -} - -SelectorTable::~SelectorTable() { - delete static_cast *>(Impl); -} - -//===----------------------------------------------------------------------===// -// Serialization for IdentifierInfo and IdentifierTable. -//===----------------------------------------------------------------------===// - -void IdentifierInfo::Emit(llvm::Serializer& S) const { - S.EmitInt(getTokenID()); - S.EmitInt(getBuiltinID()); - S.EmitInt(getObjCKeywordID()); - S.EmitBool(hasMacroDefinition()); - S.EmitBool(isExtensionToken()); - S.EmitBool(isPoisoned()); - S.EmitBool(isCPlusPlusOperatorKeyword()); - // FIXME: FETokenInfo -} - -void IdentifierInfo::Read(llvm::Deserializer& D) { - setTokenID((tok::TokenKind) D.ReadInt()); - setBuiltinID(D.ReadInt()); - setObjCKeywordID((tok::ObjCKeywordKind) D.ReadInt()); - setHasMacroDefinition(D.ReadBool()); - setIsExtensionToken(D.ReadBool()); - setIsPoisoned(D.ReadBool()); - setIsCPlusPlusOperatorKeyword(D.ReadBool()); - // FIXME: FETokenInfo -} - -void IdentifierTable::Emit(llvm::Serializer& S) const { - S.EnterBlock(); - - S.EmitPtr(this); - - for (iterator I=begin(), E=end(); I != E; ++I) { - const char* Key = I->getKeyData(); - const IdentifierInfo* Info = &I->getValue(); - - bool KeyRegistered = S.isRegistered(Key); - bool InfoRegistered = S.isRegistered(Info); - - if (KeyRegistered || InfoRegistered) { - // These acrobatics are so that we don't incur the cost of registering - // a pointer with the backpatcher during deserialization if nobody - // references the object. - S.EmitPtr(InfoRegistered ? Info : NULL); - S.EmitPtr(KeyRegistered ? Key : NULL); - S.EmitCStr(Key); - S.Emit(*Info); - } - } - - S.ExitBlock(); -} - -IdentifierTable* IdentifierTable::CreateAndRegister(llvm::Deserializer& D) { - llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); - - std::vector buff; - buff.reserve(200); - - IdentifierTable* t = new IdentifierTable(); - D.RegisterPtr(t); - - while (!D.FinishedBlock(BLoc)) { - llvm::SerializedPtrID InfoPtrID = D.ReadPtrID(); - llvm::SerializedPtrID KeyPtrID = D.ReadPtrID(); - - D.ReadCStr(buff); - - llvm::StringMapEntry& Entry = - t->HashTable.GetOrCreateValue(&buff[0],&buff[0]+buff.size()); - - D.Read(Entry.getValue()); - - if (InfoPtrID) - D.RegisterRef(InfoPtrID,Entry.getValue()); - - if (KeyPtrID) - D.RegisterPtr(KeyPtrID,Entry.getKeyData()); - } - - return t; -} - -//===----------------------------------------------------------------------===// -// Serialization for Selector and SelectorTable. -//===----------------------------------------------------------------------===// - -void Selector::Emit(llvm::Serializer& S) const { - S.EmitInt(getIdentifierInfoFlag()); - S.EmitPtr(reinterpret_cast(InfoPtr & ~ArgFlags)); -} - -Selector Selector::ReadVal(llvm::Deserializer& D) { - unsigned flag = D.ReadInt(); - - uintptr_t ptr; - D.ReadUIntPtr(ptr,false); // No backpatching. - - return Selector(ptr | flag); -} - -void SelectorTable::Emit(llvm::Serializer& S) const { - typedef llvm::FoldingSet::iterator iterator; - llvm::FoldingSet *SelTab; - SelTab = static_cast *>(Impl); - - S.EnterBlock(); - - S.EmitPtr(this); - - for (iterator I=SelTab->begin(), E=SelTab->end(); I != E; ++I) { - if (!S.isRegistered(&*I)) - continue; - - S.FlushRecord(); // Start a new record. - - S.EmitPtr(&*I); - S.EmitInt(I->getNumArgs()); - - for (MultiKeywordSelector::keyword_iterator KI = I->keyword_begin(), - KE = I->keyword_end(); KI != KE; ++KI) - S.EmitPtr(*KI); - } - - S.ExitBlock(); -} - -SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer& D) { - llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); - - SelectorTable* t = new SelectorTable(); - D.RegisterPtr(t); - - llvm::FoldingSet& SelTab = - *static_cast*>(t->Impl); - - while (!D.FinishedBlock(BLoc)) { - - llvm::SerializedPtrID PtrID = D.ReadPtrID(); - unsigned nKeys = D.ReadInt(); - - MultiKeywordSelector *SI = - (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + - nKeys*sizeof(IdentifierInfo *)); - - new (SI) MultiKeywordSelector(nKeys); - - D.RegisterPtr(PtrID,SI); - - IdentifierInfo **KeyInfo = reinterpret_cast(SI+1); - - for (unsigned i = 0; i != nKeys; ++i) - D.ReadPtr(KeyInfo[i],false); - - SelTab.GetOrInsertNode(SI); - } - - return t; -} diff --git a/clang/Basic/LangOptions.cpp b/clang/Basic/LangOptions.cpp deleted file mode 100644 index f7fd91fbda5..00000000000 --- a/clang/Basic/LangOptions.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===--- LangOptions.cpp - Language feature info --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the methods for LangOptions. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/LangOptions.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using namespace clang; - -void LangOptions::Emit(llvm::Serializer& S) const { - S.EmitBool((bool) Trigraphs); - S.EmitBool((bool) BCPLComment); - S.EmitBool((bool) DollarIdents); - S.EmitBool((bool) Digraphs); - S.EmitBool((bool) HexFloats); - S.EmitBool((bool) C99); - S.EmitBool((bool) Microsoft); - S.EmitBool((bool) CPlusPlus); - S.EmitBool((bool) CPlusPlus0x); - S.EmitBool((bool) NoExtensions); - S.EmitBool((bool) CXXOperatorNames); - S.EmitBool((bool) ObjC1); - S.EmitBool((bool) ObjC2); - S.EmitBool((bool) PascalStrings); - S.EmitBool((bool) Boolean); - S.EmitBool((bool) WritableStrings); - S.EmitBool((bool) LaxVectorConversions); -} - -void LangOptions::Read(llvm::Deserializer& D) { - Trigraphs = D.ReadBool() ? 1 : 0; - BCPLComment = D.ReadBool() ? 1 : 0; - DollarIdents = D.ReadBool() ? 1 : 0; - Digraphs = D.ReadBool() ? 1 : 0; - HexFloats = D.ReadBool() ? 1 : 0; - C99 = D.ReadBool() ? 1 : 0; - Microsoft = D.ReadBool() ? 1 : 0; - CPlusPlus = D.ReadBool() ? 1 : 0; - CPlusPlus0x = D.ReadBool() ? 1 : 0; - NoExtensions = D.ReadBool() ? 1 : 0; - CXXOperatorNames = D.ReadBool() ? 1 : 0; - ObjC1 = D.ReadBool() ? 1 : 0; - ObjC2 = D.ReadBool() ? 1 : 0; - PascalStrings = D.ReadBool() ? 1 : 0; - Boolean = D.ReadBool() ? 1 : 0; - WritableStrings = D.ReadBool() ? 1 : 0; - LaxVectorConversions = D.ReadBool() ? 1 : 0; -} diff --git a/clang/Basic/Makefile b/clang/Basic/Makefile deleted file mode 100644 index 1fa8f581b6b..00000000000 --- a/clang/Basic/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -##===- clang/Basic/Makefile --------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the Basic library for the C-Language front-end. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangBasic -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/Basic/SourceLocation.cpp b/clang/Basic/SourceLocation.cpp deleted file mode 100644 index eaf129f251e..00000000000 --- a/clang/Basic/SourceLocation.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//==--- SourceLocation.cpp - Compact identifier for Source Files -*- 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 serialization methods for the SourceLocation class. -// This file defines accessor methods for the FullSourceLoc class. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" - -using namespace clang; - -void SourceLocation::Emit(llvm::Serializer& S) const { - S.EmitInt(getRawEncoding()); -} - -SourceLocation SourceLocation::ReadVal(llvm::Deserializer& D) { - return SourceLocation::getFromRawEncoding(D.ReadInt()); -} - -void SourceRange::Emit(llvm::Serializer& S) const { - B.Emit(S); - E.Emit(S); -} - -SourceRange SourceRange::ReadVal(llvm::Deserializer& D) { - SourceLocation A = SourceLocation::ReadVal(D); - SourceLocation B = SourceLocation::ReadVal(D); - return SourceRange(A,B); -} - -FullSourceLoc FullSourceLoc::getLogicalLoc() { - assert (isValid()); - return FullSourceLoc(SrcMgr->getLogicalLoc(Loc),*SrcMgr); -} - -FullSourceLoc FullSourceLoc::getIncludeLoc() { - assert (isValid()); - return FullSourceLoc(SrcMgr->getIncludeLoc(Loc),*SrcMgr); -} - -unsigned FullSourceLoc::getLineNumber() { - assert (isValid()); - return SrcMgr->getLineNumber(Loc); -} - -unsigned FullSourceLoc::getColumnNumber() { - assert (isValid()); - return SrcMgr->getColumnNumber(Loc); -} - -const char* FullSourceLoc::getSourceName() const { - assert (isValid()); - return SrcMgr->getSourceName(Loc); -} - -const FileEntry* FullSourceLoc::getFileEntryForLoc() const { - assert (isValid()); - return SrcMgr->getFileEntryForLoc(Loc); -} - -const char * FullSourceLoc::getCharacterData() const { - assert (isValid()); - return SrcMgr->getCharacterData(Loc); -} - -const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { - assert (isValid()); - return SrcMgr->getBuffer(Loc.getFileID()); -} diff --git a/clang/Basic/SourceManager.cpp b/clang/Basic/SourceManager.cpp deleted file mode 100644 index 73ac2abe26f..00000000000 --- a/clang/Basic/SourceManager.cpp +++ /dev/null @@ -1,574 +0,0 @@ -//===--- SourceManager.cpp - Track and cache source files -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the SourceManager interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" -#include "llvm/Config/config.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Path.h" -#include "llvm/Bitcode/Serialize.h" -#include "llvm/Bitcode/Deserialize.h" -#include "llvm/Support/Streams.h" -#include -#include -using namespace clang; -using namespace SrcMgr; -using llvm::MemoryBuffer; - -ContentCache::~ContentCache() { - delete Buffer; - delete [] SourceLineCache; -} - -// FIXME: REMOVE THESE -#include -#include -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#include -#else -#include -#endif -#include - -static const MemoryBuffer *ReadFileFast(const FileEntry *FileEnt) { -#if 0 - // FIXME: Reintroduce this and zap this function once the common llvm stuff - // is fast for the small case. - return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()), - FileEnt->getSize()); -#endif - - // If the file is larger than some threshold, use 'read', otherwise use mmap. - if (FileEnt->getSize() >= 4096*4) - return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()), - 0, FileEnt->getSize()); - - MemoryBuffer *SB = MemoryBuffer::getNewUninitMemBuffer(FileEnt->getSize(), - FileEnt->getName()); - char *BufPtr = const_cast(SB->getBufferStart()); - -#if defined(LLVM_ON_WIN32) - int FD = ::open(FileEnt->getName(), O_RDONLY|O_BINARY); -#else - int FD = ::open(FileEnt->getName(), O_RDONLY); -#endif - if (FD == -1) { - delete SB; - return 0; - } - - unsigned BytesLeft = FileEnt->getSize(); - while (BytesLeft) { - ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); - if (NumRead != -1) { - BytesLeft -= NumRead; - BufPtr += NumRead; - } else if (errno == EINTR) { - // try again - } else { - // error reading. - close(FD); - delete SB; - return 0; - } - } - close(FD); - - return SB; -} - - -/// getFileInfo - Create or return a cached FileInfo for the specified file. -/// -const ContentCache* SourceManager::getContentCache(const FileEntry *FileEnt) { - - assert(FileEnt && "Didn't specify a file entry to use?"); - // Do we already have information about this file? - std::set::iterator I = - FileInfos.lower_bound(ContentCache(FileEnt)); - - if (I != FileInfos.end() && I->Entry == FileEnt) - return &*I; - - // Nope, get information. - const MemoryBuffer *File = ReadFileFast(FileEnt); - if (File == 0) - return 0; - - ContentCache& Entry = const_cast(*FileInfos.insert(I,FileEnt)); - - Entry.Buffer = File; - Entry.SourceLineCache = 0; - Entry.NumLines = 0; - return &Entry; -} - - -/// createMemBufferContentCache - Create a new ContentCache for the specified -/// memory buffer. This does no caching. -const ContentCache* -SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { - // Add a new ContentCache to the MemBufferInfos list and return it. We - // must default construct the object first that the instance actually - // stored within MemBufferInfos actually owns the Buffer, and not any - // temporary we would use in the call to "push_back". - MemBufferInfos.push_back(ContentCache()); - ContentCache& Entry = const_cast(MemBufferInfos.back()); - Entry.Buffer = Buffer; - return &Entry; -} - - -/// createFileID - Create a new fileID for the specified ContentCache and -/// include position. This works regardless of whether the ContentCache -/// corresponds to a file or some other input source. -unsigned SourceManager::createFileID(const ContentCache *File, - SourceLocation IncludePos) { - // If FileEnt is really large (e.g. it's a large .i file), we may not be able - // to fit an arbitrary position in the file in the FilePos field. To handle - // this, we create one FileID for each chunk of the file that fits in a - // FilePos field. - unsigned FileSize = File->Buffer->getBufferSize(); - if (FileSize+1 < (1 << SourceLocation::FilePosBits)) { - FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File)); - assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && - "Ran out of file ID's!"); - return FileIDs.size(); - } - - // Create one FileID for each chunk of the file. - unsigned Result = FileIDs.size()+1; - - unsigned ChunkNo = 0; - while (1) { - FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File)); - - if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break; - FileSize -= (1 << SourceLocation::FilePosBits); - } - - assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && - "Ran out of file ID's!"); - return Result; -} - -/// getInstantiationLoc - Return a new SourceLocation that encodes the fact -/// that a token from physloc PhysLoc should actually be referenced from -/// InstantiationLoc. -SourceLocation SourceManager::getInstantiationLoc(SourceLocation PhysLoc, - SourceLocation InstantLoc) { - // The specified source location may be a mapped location, due to a macro - // instantiation or #line directive. Strip off this information to find out - // where the characters are actually located. - PhysLoc = getPhysicalLoc(PhysLoc); - - // Resolve InstantLoc down to a real logical location. - InstantLoc = getLogicalLoc(InstantLoc); - - - // If the last macro id is close to the currently requested location, try to - // reuse it. This implements a small cache. - for (int i = MacroIDs.size()-1, e = MacroIDs.size()-6; i >= 0 && i != e; --i){ - MacroIDInfo &LastOne = MacroIDs[i]; - - // The instanitation point and source physloc have to exactly match to reuse - // (for now). We could allow "nearby" instantiations in the future. - if (LastOne.getVirtualLoc() != InstantLoc || - LastOne.getPhysicalLoc().getFileID() != PhysLoc.getFileID()) - continue; - - // Check to see if the physloc of the token came from near enough to reuse. - int PhysDelta = PhysLoc.getRawFilePos() - - LastOne.getPhysicalLoc().getRawFilePos(); - if (SourceLocation::isValidMacroPhysOffs(PhysDelta)) - return SourceLocation::getMacroLoc(i, PhysDelta); - } - - - MacroIDs.push_back(MacroIDInfo::get(InstantLoc, PhysLoc)); - return SourceLocation::getMacroLoc(MacroIDs.size()-1, 0); -} - -/// getBufferData - Return a pointer to the start and end of the character -/// data for the specified FileID. -std::pair -SourceManager::getBufferData(unsigned FileID) const { - const llvm::MemoryBuffer *Buf = getBuffer(FileID); - return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); -} - - -/// getCharacterData - Return a pointer to the start of the specified location -/// in the appropriate MemoryBuffer. -const char *SourceManager::getCharacterData(SourceLocation SL) const { - // Note that this is a hot function in the getSpelling() path, which is - // heavily used by -E mode. - SL = getPhysicalLoc(SL); - - return getContentCache(SL.getFileID())->Buffer->getBufferStart() + - getFullFilePos(SL); -} - - -/// getColumnNumber - Return the column # for the specified file position. -/// this is significantly cheaper to compute than the line number. This returns -/// zero if the column number isn't known. -unsigned SourceManager::getColumnNumber(SourceLocation Loc) const { - unsigned FileID = Loc.getFileID(); - if (FileID == 0) return 0; - - unsigned FilePos = getFullFilePos(Loc); - const MemoryBuffer *Buffer = getBuffer(FileID); - const char *Buf = Buffer->getBufferStart(); - - unsigned LineStart = FilePos; - while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') - --LineStart; - return FilePos-LineStart+1; -} - -/// getSourceName - This method returns the name of the file or buffer that -/// the SourceLocation specifies. This can be modified with #line directives, -/// etc. -const char *SourceManager::getSourceName(SourceLocation Loc) const { - unsigned FileID = Loc.getFileID(); - if (FileID == 0) return ""; - return getContentCache(FileID)->Buffer->getBufferIdentifier(); -} - -static void ComputeLineNumbers(ContentCache* FI) DISABLE_INLINE; -static void ComputeLineNumbers(ContentCache* FI) { - const MemoryBuffer *Buffer = FI->Buffer; - - // Find the file offsets of all of the *physical* source lines. This does - // not look at trigraphs, escaped newlines, or anything else tricky. - std::vector LineOffsets; - - // Line #1 starts at char 0. - LineOffsets.push_back(0); - - const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); - const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); - unsigned Offs = 0; - while (1) { - // Skip over the contents of the line. - // TODO: Vectorize this? This is very performance sensitive for programs - // with lots of diagnostics and in -E mode. - const unsigned char *NextBuf = (const unsigned char *)Buf; - while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') - ++NextBuf; - Offs += NextBuf-Buf; - Buf = NextBuf; - - if (Buf[0] == '\n' || Buf[0] == '\r') { - // If this is \n\r or \r\n, skip both characters. - if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) - ++Offs, ++Buf; - ++Offs, ++Buf; - LineOffsets.push_back(Offs); - } else { - // Otherwise, this is a null. If end of file, exit. - if (Buf == End) break; - // Otherwise, skip the null. - ++Offs, ++Buf; - } - } - - // Copy the offsets into the FileInfo structure. - FI->NumLines = LineOffsets.size(); - FI->SourceLineCache = new unsigned[LineOffsets.size()]; - std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache); -} - -/// getLineNumber - Given a SourceLocation, return the physical line number -/// for the position indicated. This requires building and caching a table of -/// line offsets for the MemoryBuffer, so this is not cheap: use only when -/// about to emit a diagnostic. -unsigned SourceManager::getLineNumber(SourceLocation Loc) { - unsigned FileID = Loc.getFileID(); - if (FileID == 0) return 0; - - ContentCache* Content; - - if (LastLineNoFileIDQuery == FileID) - Content = LastLineNoContentCache; - else - Content = const_cast(getContentCache(FileID)); - - // If this is the first use of line information for this buffer, compute the - /// SourceLineCache for it on demand. - if (Content->SourceLineCache == 0) - ComputeLineNumbers(Content); - - // Okay, we know we have a line number table. Do a binary search to find the - // line number that this character position lands on. - unsigned *SourceLineCache = Content->SourceLineCache; - unsigned *SourceLineCacheStart = SourceLineCache; - unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines; - - unsigned QueriedFilePos = getFullFilePos(Loc)+1; - - // If the previous query was to the same file, we know both the file pos from - // that query and the line number returned. This allows us to narrow the - // search space from the entire file to something near the match. - if (LastLineNoFileIDQuery == FileID) { - if (QueriedFilePos >= LastLineNoFilePos) { - SourceLineCache = SourceLineCache+LastLineNoResult-1; - - // The query is likely to be nearby the previous one. Here we check to - // see if it is within 5, 10 or 20 lines. It can be far away in cases - // where big comment blocks and vertical whitespace eat up lines but - // contribute no tokens. - if (SourceLineCache+5 < SourceLineCacheEnd) { - if (SourceLineCache[5] > QueriedFilePos) - SourceLineCacheEnd = SourceLineCache+5; - else if (SourceLineCache+10 < SourceLineCacheEnd) { - if (SourceLineCache[10] > QueriedFilePos) - SourceLineCacheEnd = SourceLineCache+10; - else if (SourceLineCache+20 < SourceLineCacheEnd) { - if (SourceLineCache[20] > QueriedFilePos) - SourceLineCacheEnd = SourceLineCache+20; - } - } - } - } else { - SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; - } - } - - // If the spread is large, do a "radix" test as our initial guess, based on - // the assumption that lines average to approximately the same length. - // NOTE: This is currently disabled, as it does not appear to be profitable in - // initial measurements. - if (0 && SourceLineCacheEnd-SourceLineCache > 20) { - unsigned FileLen = Content->SourceLineCache[Content->NumLines-1]; - - // Take a stab at guessing where it is. - unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen; - - // Check for -10 and +10 lines. - unsigned LowerBound = std::max(int(ApproxPos-10), 0); - unsigned UpperBound = std::min(ApproxPos+10, FileLen); - - // If the computed lower bound is less than the query location, move it in. - if (SourceLineCache < SourceLineCacheStart+LowerBound && - SourceLineCacheStart[LowerBound] < QueriedFilePos) - SourceLineCache = SourceLineCacheStart+LowerBound; - - // If the computed upper bound is greater than the query location, move it. - if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound && - SourceLineCacheStart[UpperBound] >= QueriedFilePos) - SourceLineCacheEnd = SourceLineCacheStart+UpperBound; - } - - unsigned *Pos - = std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos); - unsigned LineNo = Pos-SourceLineCacheStart; - - LastLineNoFileIDQuery = FileID; - LastLineNoContentCache = Content; - LastLineNoFilePos = QueriedFilePos; - LastLineNoResult = LineNo; - return LineNo; -} - -/// PrintStats - Print statistics to stderr. -/// -void SourceManager::PrintStats() const { - llvm::cerr << "\n*** Source Manager Stats:\n"; - llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size() - << " mem buffers mapped, " << FileIDs.size() - << " file ID's allocated.\n"; - llvm::cerr << " " << FileIDs.size() << " normal buffer FileID's, " - << MacroIDs.size() << " macro expansion FileID's.\n"; - - unsigned NumLineNumsComputed = 0; - unsigned NumFileBytesMapped = 0; - for (std::set::const_iterator I = - FileInfos.begin(), E = FileInfos.end(); I != E; ++I) { - NumLineNumsComputed += I->SourceLineCache != 0; - NumFileBytesMapped += I->Buffer->getBufferSize(); - } - - llvm::cerr << NumFileBytesMapped << " bytes of files mapped, " - << NumLineNumsComputed << " files with line #'s computed.\n"; -} - -//===----------------------------------------------------------------------===// -// Serialization. -//===----------------------------------------------------------------------===// - -void ContentCache::Emit(llvm::Serializer& S) const { - S.FlushRecord(); - S.EmitPtr(this); - - if (Entry) { - llvm::sys::Path Fname(Buffer->getBufferIdentifier()); - - if (Fname.isAbsolute()) - S.EmitCStr(Fname.c_str()); - else { - // Create an absolute path. - // FIXME: This will potentially contain ".." and "." in the path. - llvm::sys::Path path = llvm::sys::Path::GetCurrentDirectory(); - path.appendComponent(Fname.c_str()); - S.EmitCStr(path.c_str()); - } - } - else { - const char* p = Buffer->getBufferStart(); - const char* e = Buffer->getBufferEnd(); - - S.EmitInt(e-p); - - for ( ; p != e; ++p) - S.EmitInt(*p); - } - - S.FlushRecord(); -} - -void ContentCache::ReadToSourceManager(llvm::Deserializer& D, - SourceManager& SMgr, - FileManager* FMgr, - std::vector& Buf) { - if (FMgr) { - llvm::SerializedPtrID PtrID = D.ReadPtrID(); - D.ReadCStr(Buf,false); - - // Create/fetch the FileEntry. - const char* start = &Buf[0]; - const FileEntry* E = FMgr->getFile(start,start+Buf.size()); - - // FIXME: Ideally we want a lazy materialization of the ContentCache - // anyway, because we don't want to read in source files unless this - // is absolutely needed. - if (!E) - D.RegisterPtr(PtrID,NULL); - else - // Get the ContextCache object and register it with the deserializer. - D.RegisterPtr(PtrID,SMgr.getContentCache(E)); - } - else { - // Register the ContextCache object with the deserializer. - SMgr.MemBufferInfos.push_back(ContentCache()); - ContentCache& Entry = const_cast(SMgr.MemBufferInfos.back()); - D.RegisterPtr(&Entry); - - // Create the buffer. - unsigned Size = D.ReadInt(); - Entry.Buffer = MemoryBuffer::getNewUninitMemBuffer(Size); - - // Read the contents of the buffer. - char* p = const_cast(Entry.Buffer->getBufferStart()); - for (unsigned i = 0; i < Size ; ++i) - p[i] = D.ReadInt(); - } -} - -void FileIDInfo::Emit(llvm::Serializer& S) const { - S.Emit(IncludeLoc); - S.EmitInt(ChunkNo); - S.EmitPtr(Content); -} - -FileIDInfo FileIDInfo::ReadVal(llvm::Deserializer& D) { - FileIDInfo I; - I.IncludeLoc = SourceLocation::ReadVal(D); - I.ChunkNo = D.ReadInt(); - D.ReadPtr(I.Content,false); - return I; -} - -void MacroIDInfo::Emit(llvm::Serializer& S) const { - S.Emit(VirtualLoc); - S.Emit(PhysicalLoc); -} - -MacroIDInfo MacroIDInfo::ReadVal(llvm::Deserializer& D) { - MacroIDInfo I; - I.VirtualLoc = SourceLocation::ReadVal(D); - I.PhysicalLoc = SourceLocation::ReadVal(D); - return I; -} - -void SourceManager::Emit(llvm::Serializer& S) const { - S.EnterBlock(); - S.EmitPtr(this); - S.EmitInt(MainFileID); - - // Emit: FileInfos. Just emit the file name. - S.EnterBlock(); - - std::for_each(FileInfos.begin(),FileInfos.end(), - S.MakeEmitter()); - - S.ExitBlock(); - - // Emit: MemBufferInfos - S.EnterBlock(); - - std::for_each(MemBufferInfos.begin(), MemBufferInfos.end(), - S.MakeEmitter()); - - S.ExitBlock(); - - // Emit: FileIDs - S.EmitInt(FileIDs.size()); - std::for_each(FileIDs.begin(), FileIDs.end(), S.MakeEmitter()); - - // Emit: MacroIDs - S.EmitInt(MacroIDs.size()); - std::for_each(MacroIDs.begin(), MacroIDs.end(), S.MakeEmitter()); - - S.ExitBlock(); -} - -SourceManager* -SourceManager::CreateAndRegister(llvm::Deserializer& D, FileManager& FMgr){ - SourceManager *M = new SourceManager(); - D.RegisterPtr(M); - - // Read: the FileID of the main source file of the translation unit. - M->MainFileID = D.ReadInt(); - - std::vector Buf; - - { // Read: FileInfos. - llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); - while (!D.FinishedBlock(BLoc)) - ContentCache::ReadToSourceManager(D,*M,&FMgr,Buf); - } - - { // Read: MemBufferInfos. - llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); - while (!D.FinishedBlock(BLoc)) - ContentCache::ReadToSourceManager(D,*M,NULL,Buf); - } - - // Read: FileIDs. - unsigned Size = D.ReadInt(); - M->FileIDs.reserve(Size); - for (; Size > 0 ; --Size) - M->FileIDs.push_back(FileIDInfo::ReadVal(D)); - - // Read: MacroIDs. - Size = D.ReadInt(); - M->MacroIDs.reserve(Size); - for (; Size > 0 ; --Size) - M->MacroIDs.push_back(MacroIDInfo::ReadVal(D)); - - return M; -} diff --git a/clang/Basic/TargetInfo.cpp b/clang/Basic/TargetInfo.cpp deleted file mode 100644 index 0a561d75cb8..00000000000 --- a/clang/Basic/TargetInfo.cpp +++ /dev/null @@ -1,210 +0,0 @@ -//===--- TargetInfo.cpp - Information about Target machine ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the TargetInfo and TargetInfoImpl interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/AST/Builtins.h" -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/STLExtras.h" -using namespace clang; - -// TargetInfo Constructor. -TargetInfo::TargetInfo(const std::string &T) : Triple(T) { - // Set defaults. These should be overridden by concrete targets as needed. - CharIsSigned = true; - WCharWidth = WCharAlign = 32; - FloatFormat = &llvm::APFloat::IEEEsingle; - DoubleFormat = &llvm::APFloat::IEEEdouble; - LongDoubleFormat = &llvm::APFloat::IEEEdouble; -} - -// Out of line virtual dtor for TargetInfo. -TargetInfo::~TargetInfo() {} - -//===----------------------------------------------------------------------===// - - -static void removeGCCRegisterPrefix(const char *&Name) { - if (Name[0] == '%' || Name[0] == '#') - Name++; -} - -/// isValidGCCRegisterName - Returns whether the passed in string -/// is a valid register name according to GCC. This is used by Sema for -/// inline asm statements. -bool TargetInfo::isValidGCCRegisterName(const char *Name) const { - const char * const *Names; - unsigned NumNames; - - // Get rid of any register prefix. - removeGCCRegisterPrefix(Name); - - - if (strcmp(Name, "memory") == 0 || - strcmp(Name, "cc") == 0) - return true; - - getGCCRegNames(Names, NumNames); - - // If we have a number it maps to an entry in the register name array. - if (isdigit(Name[0])) { - char *End; - int n = (int)strtol(Name, &End, 0); - if (*End == 0) - return n >= 0 && (unsigned)n < NumNames; - } - - // Check register names. - for (unsigned i = 0; i < NumNames; i++) { - if (strcmp(Name, Names[i]) == 0) - return true; - } - - // Now check aliases. - const GCCRegAlias *Aliases; - unsigned NumAliases; - - getGCCRegAliases(Aliases, NumAliases); - for (unsigned i = 0; i < NumAliases; i++) { - for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { - if (!Aliases[i].Aliases[j]) - break; - if (strcmp(Aliases[i].Aliases[j], Name) == 0) - return true; - } - } - - return false; -} - -const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { - assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); - - removeGCCRegisterPrefix(Name); - - const char * const *Names; - unsigned NumNames; - - getGCCRegNames(Names, NumNames); - - // First, check if we have a number. - if (isdigit(Name[0])) { - char *End; - int n = (int)strtol(Name, &End, 0); - if (*End == 0) { - assert(n >= 0 && (unsigned)n < NumNames && - "Out of bounds register number!"); - return Names[n]; - } - } - - // Now check aliases. - const GCCRegAlias *Aliases; - unsigned NumAliases; - - getGCCRegAliases(Aliases, NumAliases); - for (unsigned i = 0; i < NumAliases; i++) { - for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { - if (!Aliases[i].Aliases[j]) - break; - if (strcmp(Aliases[i].Aliases[j], Name) == 0) - return Aliases[i].Register; - } - } - - return Name; -} - -bool TargetInfo::validateOutputConstraint(const char *Name, - ConstraintInfo &info) const -{ - // An output constraint must start with '=' or '+' - if (*Name != '=' && *Name != '+') - return false; - - if (*Name == '+') - info = CI_ReadWrite; - else - info = CI_None; - - Name++; - while (*Name) { - switch (*Name) { - default: - if (!validateAsmConstraint(*Name, info)) { - // FIXME: This assert is in place temporarily - // so we can add more constraints as we hit it. - // Eventually, an unknown constraint should just be treated as 'g'. - assert(0 && "Unknown output constraint type!"); - } - case '&': // early clobber. - break; - case 'r': // general register. - info = (ConstraintInfo)(info|CI_AllowsRegister); - break; - case 'm': // memory operand. - info = (ConstraintInfo)(info|CI_AllowsMemory); - break; - case 'g': // general register, memory operand or immediate integer. - info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister); - break; - } - - Name++; - } - - return true; -} - -bool TargetInfo::validateInputConstraint(const char *Name, - unsigned NumOutputs, - ConstraintInfo &info) const { - while (*Name) { - switch (*Name) { - default: - // Check if we have a matching constraint - if (*Name >= '0' && *Name <= '9') { - unsigned i = *Name - '0'; - - // Check if matching constraint is out of bounds. - if (i >= NumOutputs) - return false; - } else if (!validateAsmConstraint(*Name, info)) { - // FIXME: This assert is in place temporarily - // so we can add more constraints as we hit it. - // Eventually, an unknown constraint should just be treated as 'g'. - assert(0 && "Unknown input constraint type!"); - } - case '%': // commutative - // FIXME: Fail if % is used with the last operand. - break; - case 'i': // immediate integer. - case 'I': - case 'n': // immediate integer with a known value. - break; - case 'r': // general register. - info = (ConstraintInfo)(info|CI_AllowsRegister); - break; - case 'm': // memory operand. - info = (ConstraintInfo)(info|CI_AllowsMemory); - break; - case 'g': // general register, memory operand or immediate integer. - info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister); - break; - } - - Name++; - } - - return true; -} diff --git a/clang/Basic/Targets.cpp b/clang/Basic/Targets.cpp deleted file mode 100644 index e8238daeae3..00000000000 --- a/clang/Basic/Targets.cpp +++ /dev/null @@ -1,757 +0,0 @@ -//===--- Targets.cpp - Implement -arch option and targets -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements construction of a TargetInfo object from a -// target triple. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/Builtins.h" -#include "clang/AST/TargetBuiltins.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/STLExtras.h" - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Common code shared among targets. -//===----------------------------------------------------------------------===// - -static void Define(std::vector &Buf, const char *Macro, - const char *Val = "1") { - const char *Def = "#define "; - Buf.insert(Buf.end(), Def, Def+strlen(Def)); - Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); - Buf.push_back(' '); - Buf.insert(Buf.end(), Val, Val+strlen(Val)); - Buf.push_back('\n'); -} - - -namespace { -class DarwinTargetInfo : public TargetInfo { -public: - DarwinTargetInfo(const std::string& triple) : TargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defs) const { -// FIXME: we need a real target configuration system. For now, only define -// __APPLE__ if the host has it. -#ifdef __APPLE__ - Define(Defs, "__APPLE__"); - Define(Defs, "__MACH__"); -#endif - - if (1) {// -fobjc-gc controls this. - Define(Defs, "__weak", ""); - Define(Defs, "__strong", ""); - } else { - Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); - Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); - Define(Defs, "__OBJC_GC__"); - } - - // darwin_constant_cfstrings controls this. - Define(Defs, "__CONSTANT_CFSTRINGS__"); - - if (0) // darwin_pascal_strings - Define(Defs, "__PASCAL_STRINGS__"); - } - -}; - - -class SolarisTargetInfo : public TargetInfo { -public: - SolarisTargetInfo(const std::string& triple) : TargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defs) const { -// FIXME: we need a real target configuration system. For now, only define -// __SUN__ if the host has it. -#ifdef __SUN__ - Define(Defs, "__SUN__"); - Define(Defs, "__SOLARIS__"); -#endif - - if (1) {// -fobjc-gc controls this. - Define(Defs, "__weak", ""); - Define(Defs, "__strong", ""); - } else { - Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); - Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); - Define(Defs, "__OBJC_GC__"); - } - } - -}; -} // end anonymous namespace. - - -/// getPowerPCDefines - Return a set of the PowerPC-specific #defines that are -/// not tied to a specific subtarget. -static void getPowerPCDefines(std::vector &Defs, bool is64Bit) { - // Target identification. - Define(Defs, "__ppc__"); - Define(Defs, "_ARCH_PPC"); - Define(Defs, "__POWERPC__"); - if (is64Bit) { - Define(Defs, "_ARCH_PPC64"); - Define(Defs, "_LP64"); - Define(Defs, "__LP64__"); - Define(Defs, "__ppc64__"); - } else { - Define(Defs, "__ppc__"); - } - - // Target properties. - Define(Defs, "_BIG_ENDIAN"); - Define(Defs, "__BIG_ENDIAN__"); - - if (is64Bit) { - Define(Defs, "__INTMAX_MAX__", "9223372036854775807L"); - Define(Defs, "__INTMAX_TYPE__", "long int"); - Define(Defs, "__LONG_MAX__", "9223372036854775807L"); - Define(Defs, "__PTRDIFF_TYPE__", "long int"); - Define(Defs, "__UINTMAX_TYPE__", "long unsigned int"); - } else { - Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL"); - Define(Defs, "__INTMAX_TYPE__", "long long int"); - Define(Defs, "__LONG_MAX__", "2147483647L"); - Define(Defs, "__PTRDIFF_TYPE__", "int"); - Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int"); - } - Define(Defs, "__INT_MAX__", "2147483647"); - Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL"); - Define(Defs, "__CHAR_BIT__", "8"); - Define(Defs, "__SCHAR_MAX__", "127"); - Define(Defs, "__SHRT_MAX__", "32767"); - Define(Defs, "__SIZE_TYPE__", "long unsigned int"); - - // Subtarget options. - Define(Defs, "__USER_LABEL_PREFIX__", "_"); - Define(Defs, "__NATURAL_ALIGNMENT__"); - Define(Defs, "__REGISTER_PREFIX__", ""); - - Define(Defs, "__WCHAR_MAX__", "2147483647"); - Define(Defs, "__WCHAR_TYPE__", "int"); - Define(Defs, "__WINT_TYPE__", "int"); - - // Float macros. - Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F"); - Define(Defs, "__FLT_DIG__", "6"); - Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F"); - Define(Defs, "__FLT_EVAL_METHOD__", "0"); - Define(Defs, "__FLT_HAS_INFINITY__"); - Define(Defs, "__FLT_HAS_QUIET_NAN__"); - Define(Defs, "__FLT_MANT_DIG__", "24"); - Define(Defs, "__FLT_MAX_10_EXP__", "38"); - Define(Defs, "__FLT_MAX_EXP__", "128"); - Define(Defs, "__FLT_MAX__", "3.40282347e+38F"); - Define(Defs, "__FLT_MIN_10_EXP__", "(-37)"); - Define(Defs, "__FLT_MIN_EXP__", "(-125)"); - Define(Defs, "__FLT_MIN__", "1.17549435e-38F"); - Define(Defs, "__FLT_RADIX__", "2"); - - // double macros. - Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324"); - Define(Defs, "__DBL_DIG__", "15"); - Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16"); - Define(Defs, "__DBL_HAS_INFINITY__"); - Define(Defs, "__DBL_HAS_QUIET_NAN__"); - Define(Defs, "__DBL_MANT_DIG__", "53"); - Define(Defs, "__DBL_MAX_10_EXP__", "308"); - Define(Defs, "__DBL_MAX_EXP__", "1024"); - Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308"); - Define(Defs, "__DBL_MIN_10_EXP__", "(-307)"); - Define(Defs, "__DBL_MIN_EXP__", "(-1021)"); - Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308"); - Define(Defs, "__DECIMAL_DIG__", "33"); - - // 128-bit long double macros. - Define(Defs, "__LDBL_DENORM_MIN__", - "4.94065645841246544176568792868221e-324L"); - Define(Defs, "__LDBL_DIG__", "31"); - Define(Defs, "__LDBL_EPSILON__", - "4.94065645841246544176568792868221e-324L"); - Define(Defs, "__LDBL_HAS_INFINITY__"); - Define(Defs, "__LDBL_HAS_QUIET_NAN__"); - Define(Defs, "__LDBL_MANT_DIG__", "106"); - Define(Defs, "__LDBL_MAX_10_EXP__", "308"); - Define(Defs, "__LDBL_MAX_EXP__", "1024"); - Define(Defs, "__LDBL_MAX__", - "1.79769313486231580793728971405301e+308L"); - Define(Defs, "__LDBL_MIN_10_EXP__", "(-291)"); - Define(Defs, "__LDBL_MIN_EXP__", "(-968)"); - Define(Defs, "__LDBL_MIN__", - "2.00416836000897277799610805135016e-292L"); - Define(Defs, "__LONG_DOUBLE_128__"); -} - -/// getX86Defines - Return a set of the X86-specific #defines that are -/// not tied to a specific subtarget. -static void getX86Defines(std::vector &Defs, bool is64Bit) { - // Target identification. - if (is64Bit) { - Define(Defs, "_LP64"); - Define(Defs, "__LP64__"); - Define(Defs, "__amd64__"); - Define(Defs, "__amd64"); - Define(Defs, "__x86_64"); - Define(Defs, "__x86_64__"); - } else { - Define(Defs, "__i386__"); - Define(Defs, "__i386"); - Define(Defs, "i386"); - } - - // Target properties. - Define(Defs, "__LITTLE_ENDIAN__"); - - if (is64Bit) { - Define(Defs, "__INTMAX_MAX__", "9223372036854775807L"); - Define(Defs, "__INTMAX_TYPE__", "long int"); - Define(Defs, "__LONG_MAX__", "9223372036854775807L"); - Define(Defs, "__PTRDIFF_TYPE__", "long int"); - Define(Defs, "__UINTMAX_TYPE__", "long unsigned int"); - Define(Defs, "__SIZE_TYPE__", "long unsigned int"); - } else { - Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL"); - Define(Defs, "__INTMAX_TYPE__", "long long int"); - Define(Defs, "__LONG_MAX__", "2147483647L"); - Define(Defs, "__PTRDIFF_TYPE__", "int"); - Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int"); - Define(Defs, "__SIZE_TYPE__", "unsigned int"); - } - Define(Defs, "__CHAR_BIT__", "8"); - Define(Defs, "__INT_MAX__", "2147483647"); - Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL"); - Define(Defs, "__SCHAR_MAX__", "127"); - Define(Defs, "__SHRT_MAX__", "32767"); - - // Subtarget options. - Define(Defs, "__nocona"); - Define(Defs, "__nocona__"); - Define(Defs, "__tune_nocona__"); - Define(Defs, "__SSE2_MATH__"); - Define(Defs, "__SSE2__"); - Define(Defs, "__SSE_MATH__"); - Define(Defs, "__SSE__"); - Define(Defs, "__MMX__"); - Define(Defs, "__REGISTER_PREFIX__", ""); - - Define(Defs, "__WCHAR_MAX__", "2147483647"); - Define(Defs, "__WCHAR_TYPE__", "int"); - Define(Defs, "__WINT_TYPE__", "int"); - - // Float macros. - Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F"); - Define(Defs, "__FLT_DIG__", "6"); - Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F"); - Define(Defs, "__FLT_EVAL_METHOD__", "0"); - Define(Defs, "__FLT_HAS_INFINITY__"); - Define(Defs, "__FLT_HAS_QUIET_NAN__"); - Define(Defs, "__FLT_MANT_DIG__", "24"); - Define(Defs, "__FLT_MAX_10_EXP__", "38"); - Define(Defs, "__FLT_MAX_EXP__", "128"); - Define(Defs, "__FLT_MAX__", "3.40282347e+38F"); - Define(Defs, "__FLT_MIN_10_EXP__", "(-37)"); - Define(Defs, "__FLT_MIN_EXP__", "(-125)"); - Define(Defs, "__FLT_MIN__", "1.17549435e-38F"); - Define(Defs, "__FLT_RADIX__", "2"); - - // Double macros. - Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324"); - Define(Defs, "__DBL_DIG__", "15"); - Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16"); - Define(Defs, "__DBL_HAS_INFINITY__"); - Define(Defs, "__DBL_HAS_QUIET_NAN__"); - Define(Defs, "__DBL_MANT_DIG__", "53"); - Define(Defs, "__DBL_MAX_10_EXP__", "308"); - Define(Defs, "__DBL_MAX_EXP__", "1024"); - Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308"); - Define(Defs, "__DBL_MIN_10_EXP__", "(-307)"); - Define(Defs, "__DBL_MIN_EXP__", "(-1021)"); - Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308"); - Define(Defs, "__DECIMAL_DIG__", "21"); - - // 80-bit Long double macros. - Define(Defs, "__LDBL_DENORM_MIN__", "3.64519953188247460253e-4951L"); - Define(Defs, "__LDBL_DIG__", "18"); - Define(Defs, "__LDBL_EPSILON__", "1.08420217248550443401e-19L"); - Define(Defs, "__LDBL_HAS_INFINITY__"); - Define(Defs, "__LDBL_HAS_QUIET_NAN__"); - Define(Defs, "__LDBL_MANT_DIG__", "64"); - Define(Defs, "__LDBL_MAX_10_EXP__", "4932"); - Define(Defs, "__LDBL_MAX_EXP__", "16384"); - Define(Defs, "__LDBL_MAX__", "1.18973149535723176502e+4932L"); - Define(Defs, "__LDBL_MIN_10_EXP__", "(-4931)"); - Define(Defs, "__LDBL_MIN_EXP__", "(-16381)"); - Define(Defs, "__LDBL_MIN__", "3.36210314311209350626e-4932L"); -} - -static const char* getI386VAListDeclaration() { - return "typedef char* __builtin_va_list;"; -} - -static const char* getX86_64VAListDeclaration() { - return - "typedef struct __va_list_tag {" - " unsigned gp_offset;" - " unsigned fp_offset;" - " void* overflow_arg_area;" - " void* reg_save_area;" - "} __builtin_va_list[1];"; -} - -static const char* getPPCVAListDeclaration() { - return - "typedef struct __va_list_tag {" - " unsigned char gpr;" - " unsigned char fpr;" - " unsigned short reserved;" - " void* overflow_arg_area;" - " void* reg_save_area;" - "} __builtin_va_list[1];"; -} - - -/// PPC builtin info. -namespace clang { -namespace PPC { - - static const Builtin::Info BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, -#include "clang/AST/PPCBuiltins.def" - }; - - static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) { - Records = BuiltinInfo; - NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin; - } - - static const char * const GCCRegNames[] = { - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", - "mq", "lr", "ctr", "ap", - "0", "1", "2", "3", "4", "5", "6", "7", - "xer", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", - "vrsave", "vscr", - "spe_acc", "spefscr", - "sfp" - }; - - static void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); - } - - static const TargetInfo::GCCRegAlias GCCRegAliases[] = { - // While some of these aliases do map to different registers - // they still share the same register name. - { { "cc", "cr0", "fr0", "r0", "v0"}, "0" }, - { { "cr1", "fr1", "r1", "sp", "v1"}, "1" }, - { { "cr2", "fr2", "r2", "toc", "v2"}, "2" }, - { { "cr3", "fr3", "r3", "v3"}, "3" }, - { { "cr4", "fr4", "r4", "v4"}, "4" }, - { { "cr5", "fr5", "r5", "v5"}, "5" }, - { { "cr6", "fr6", "r6", "v6"}, "6" }, - { { "cr7", "fr7", "r7", "v7"}, "7" }, - { { "fr8", "r8", "v8"}, "8" }, - { { "fr9", "r9", "v9"}, "9" }, - { { "fr10", "r10", "v10"}, "10" }, - { { "fr11", "r11", "v11"}, "11" }, - { { "fr12", "r12", "v12"}, "12" }, - { { "fr13", "r13", "v13"}, "13" }, - { { "fr14", "r14", "v14"}, "14" }, - { { "fr15", "r15", "v15"}, "15" }, - { { "fr16", "r16", "v16"}, "16" }, - { { "fr17", "r17", "v17"}, "17" }, - { { "fr18", "r18", "v18"}, "18" }, - { { "fr19", "r19", "v19"}, "19" }, - { { "fr20", "r20", "v20"}, "20" }, - { { "fr21", "r21", "v21"}, "21" }, - { { "fr22", "r22", "v22"}, "22" }, - { { "fr23", "r23", "v23"}, "23" }, - { { "fr24", "r24", "v24"}, "24" }, - { { "fr25", "r25", "v25"}, "25" }, - { { "fr26", "r26", "v26"}, "26" }, - { { "fr27", "r27", "v27"}, "27" }, - { { "fr28", "r28", "v28"}, "28" }, - { { "fr29", "r29", "v29"}, "29" }, - { { "fr30", "r30", "v30"}, "30" }, - { { "fr31", "r31", "v31"}, "31" }, - }; - - static void getGCCRegAliases(const TargetInfo::GCCRegAlias *&Aliases, - unsigned &NumAliases) { - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); - } - - static bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) { - switch (c) { - default: return false; - case 'O': // Zero - return true; - case 'b': // Base register - case 'f': // Floating point register - info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister); - return true; - } - } - - const char *getClobbers() { - return 0; - } - - const char *getTargetPrefix() { - return "ppc"; - } - -} // End namespace PPC - -/// X86 builtin info. -namespace X86 { - static const Builtin::Info BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, -#include "clang/AST/X86Builtins.def" - }; - - static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) { - Records = BuiltinInfo; - NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin; - } - - static const char *GCCRegNames[] = { - "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", - "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", - "argp", "flags", "fspr", "dirflag", "frame", - "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", - "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" - }; - - static void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); - } - - static const TargetInfo::GCCRegAlias GCCRegAliases[] = { - { { "al", "ah", "eax", "rax" }, "ax" }, - { { "bl", "bh", "ebx", "rbx" }, "bx" }, - { { "cl", "ch", "ecx", "rcx" }, "cx" }, - { { "dl", "dh", "edx", "rdx" }, "dx" }, - { { "esi", "rsi" }, "si" }, - { { "esp", "rsp" }, "sp" }, - { { "ebp", "rbp" }, "bp" }, - }; - - static void getGCCRegAliases(const TargetInfo::GCCRegAlias *&Aliases, - unsigned &NumAliases) { - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); - } - - static bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) { - switch (c) { - default: return false; - case 'a': // eax. - case 'b': // ebx. - case 'c': // ecx. - case 'd': // edx. - case 'S': // esi. - case 'D': // edi. - case 'A': // edx:eax. - case 't': // top of floating point stack. - case 'u': // second from top of floating point stack. - case 'q': // a, b, c, d registers or any integer register in 64-bit. - case 'Z': // 32-bit integer constant for use with zero-extending x86_64 - // instructions. - case 'N': // unsigned 8-bit integer constant for use with in and out - // instructions. - info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister); - return true; - } - } - - static std::string convertConstraint(const char Constraint) { - switch (Constraint) { - case 'a': return std::string("{ax}"); - case 'b': return std::string("{bx}"); - case 'c': return std::string("{cx}"); - case 'd': return std::string("{dx}"); - case 'S': return std::string("{si}"); - case 'D': return std::string("{di}"); - case 't': // top of floating point stack. - return std::string("{st}"); - case 'u': // second from top of floating point stack. - return std::string("{st(1)}"); // second from top of floating point stack. - default: - return std::string(1, Constraint); - } - } - - const char *getClobbers() { - return "~{dirflag},~{fpsr},~{flags}"; - } - - const char *getTargetPrefix() { - return "x86"; - } - -} // End namespace X86 -} // end namespace clang. - -//===----------------------------------------------------------------------===// -// Specific target implementations. -//===----------------------------------------------------------------------===// - - -namespace { -class DarwinPPCTargetInfo : public DarwinTargetInfo { -public: - DarwinPPCTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defines) const { - DarwinTargetInfo::getTargetDefines(Defines); - getPowerPCDefines(Defines, false); - } - virtual void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const { - PPC::getBuiltins(Records, NumRecords); - } - virtual const char *getVAListDeclaration() const { - return getPPCVAListDeclaration(); - } - virtual const char *getTargetPrefix() const { - return PPC::getTargetPrefix(); - } - virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - PPC::getGCCRegNames(Names, NumNames); - } - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - PPC::getGCCRegAliases(Aliases, NumAliases); - } - virtual bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) const { - return PPC::validateAsmConstraint(c, info); - } - virtual const char *getClobbers() const { - return PPC::getClobbers(); - } -}; -} // end anonymous namespace. - -namespace { -class DarwinPPC64TargetInfo : public DarwinTargetInfo { -public: - DarwinPPC64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defines) const { - DarwinTargetInfo::getTargetDefines(Defines); - getPowerPCDefines(Defines, true); - } - virtual void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const { - PPC::getBuiltins(Records, NumRecords); - } - virtual const char *getVAListDeclaration() const { - return getPPCVAListDeclaration(); - } - virtual const char *getTargetPrefix() const { - return PPC::getTargetPrefix(); - } - virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - PPC::getGCCRegNames(Names, NumNames); - } - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - PPC::getGCCRegAliases(Aliases, NumAliases); - } - virtual bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) const { - return PPC::validateAsmConstraint(c, info); - } - virtual const char *getClobbers() const { - return PPC::getClobbers(); - } -}; -} // end anonymous namespace. - -namespace { -class DarwinI386TargetInfo : public DarwinTargetInfo { -public: - DarwinI386TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defines) const { - DarwinTargetInfo::getTargetDefines(Defines); - getX86Defines(Defines, false); - } - virtual void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const { - X86::getBuiltins(Records, NumRecords); - } - virtual const char *getVAListDeclaration() const { - return getI386VAListDeclaration(); - } - virtual const char *getTargetPrefix() const { - return X86::getTargetPrefix(); - } - virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - X86::getGCCRegNames(Names, NumNames); - } - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - X86::getGCCRegAliases(Aliases, NumAliases); - } - virtual bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) const { - return X86::validateAsmConstraint(c, info); - } - - virtual std::string convertConstraint(const char Constraint) const { - return X86::convertConstraint(Constraint); - } - - virtual const char *getClobbers() const { - return X86::getClobbers(); - } -}; -} // end anonymous namespace. - -namespace { -class DarwinX86_64TargetInfo : public DarwinTargetInfo { -public: - DarwinX86_64TargetInfo(const std::string& triple) :DarwinTargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defines) const { - DarwinTargetInfo::getTargetDefines(Defines); - getX86Defines(Defines, true); - } - virtual void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const { - X86::getBuiltins(Records, NumRecords); - } - virtual const char *getVAListDeclaration() const { - return getX86_64VAListDeclaration(); - } - virtual const char *getTargetPrefix() const { - return X86::getTargetPrefix(); - } - virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - X86::getGCCRegNames(Names, NumNames); - } - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - X86::getGCCRegAliases(Aliases, NumAliases); - } - virtual bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) const { - return X86::validateAsmConstraint(c, info); - } - virtual std::string convertConstraint(const char Constraint) const { - return X86::convertConstraint(Constraint); - } - virtual const char *getClobbers() const { - return X86::getClobbers(); - } -}; -} // end anonymous namespace. - -namespace { -class SolarisSparcV8TargetInfo : public SolarisTargetInfo { -public: - SolarisSparcV8TargetInfo(const std::string& triple) : SolarisTargetInfo(triple) {} - - virtual void getTargetDefines(std::vector &Defines) const { - SolarisTargetInfo::getTargetDefines(Defines); -// getSparcDefines(Defines, false); - Define(Defines, "__sparc"); - Define(Defines, "__sparcv8"); - } - virtual void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const { - PPC::getBuiltins(Records, NumRecords); - } - virtual const char *getVAListDeclaration() const { - return getPPCVAListDeclaration(); - } - virtual const char *getTargetPrefix() const { - return PPC::getTargetPrefix(); - } - virtual void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - PPC::getGCCRegNames(Names, NumNames); - } - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - PPC::getGCCRegAliases(Aliases, NumAliases); - } - virtual bool validateAsmConstraint(char c, - TargetInfo::ConstraintInfo &info) const { - return PPC::validateAsmConstraint(c, info); - } - virtual const char *getClobbers() const { - return PPC::getClobbers(); - } -}; - -} // end anonymous namespace. - - -//===----------------------------------------------------------------------===// -// Driver code -//===----------------------------------------------------------------------===// - -static inline bool IsX86(const std::string& TT) { - return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' && - TT[4] == '-' && TT[1] - '3' < 6); -} - -/// CreateTargetInfo - Return the target info object for the specified target -/// triple. -TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { - if (T.find("ppc-") == 0 || T.find("powerpc-") == 0) - return new DarwinPPCTargetInfo(T); - - if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) - return new DarwinPPC64TargetInfo(T); - - if (T.find("sparc-") == 0) - return new SolarisSparcV8TargetInfo(T); // ugly hack - - if (T.find("x86_64-") == 0) - return new DarwinX86_64TargetInfo(T); - - if (IsX86(T)) - return new DarwinI386TargetInfo(T); - - return NULL; -} - diff --git a/clang/Basic/TokenKinds.cpp b/clang/Basic/TokenKinds.cpp deleted file mode 100644 index bde8a5598b4..00000000000 --- a/clang/Basic/TokenKinds.cpp +++ /dev/null @@ -1,29 +0,0 @@ -//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the TokenKind enum and support functions. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/TokenKinds.h" - -#include -using namespace clang; - -static const char * const TokNames[] = { -#define TOK(X) #X, -#define KEYWORD(X,Y) #X, -#include "clang/Basic/TokenKinds.def" - 0 -}; - -const char *tok::getTokenName(enum TokenKind Kind) { - assert(Kind < tok::NUM_TOKENS); - return TokNames[Kind]; -} diff --git a/clang/CodeGen/CGBuiltin.cpp b/clang/CodeGen/CGBuiltin.cpp deleted file mode 100644 index 83c5e60475c..00000000000 --- a/clang/CodeGen/CGBuiltin.cpp +++ /dev/null @@ -1,486 +0,0 @@ -//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Builtin calls as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Builtins.h" -#include "clang/AST/Expr.h" -#include "clang/AST/TargetBuiltins.h" -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/Intrinsics.h" -using namespace clang; -using namespace CodeGen; -using namespace llvm; - -RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - switch (BuiltinID) { - default: { - if (getContext().BuiltinInfo.isLibFunction(BuiltinID)) - return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), - E->getCallee()->getType(), E->arg_begin(), - E->getNumArgs()); - - // See if we have a target specific intrinsic. - Intrinsic::ID IntrinsicID; - const char *TargetPrefix = Target.getTargetPrefix(); - const char *BuiltinName = getContext().BuiltinInfo.GetName(BuiltinID); -#define GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN -#include "llvm/Intrinsics.gen" -#undef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN - - if (IntrinsicID != Intrinsic::not_intrinsic) { - SmallVector Args; - - Function *F = CGM.getIntrinsic(IntrinsicID); - const llvm::FunctionType *FTy = F->getFunctionType(); - - for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { - Value *ArgValue = EmitScalarExpr(E->getArg(i)); - - // If the intrinsic arg type is different from the builtin arg type - // we need to do a bit cast. - const llvm::Type *PTy = FTy->getParamType(i); - if (PTy != ArgValue->getType()) { - assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) && - "Must be able to losslessly bit cast to param"); - ArgValue = Builder.CreateBitCast(ArgValue, PTy); - } - - Args.push_back(ArgValue); - } - - Value *V = Builder.CreateCall(F, &Args[0], &Args[0] + Args.size()); - QualType BuiltinRetType = E->getType(); - - const llvm::Type *RetTy = llvm::Type::VoidTy; - if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType); - - if (RetTy != V->getType()) { - assert(V->getType()->canLosslesslyBitCastTo(RetTy) && - "Must be able to losslessly bit cast result type"); - V = Builder.CreateBitCast(V, RetTy); - } - - return RValue::get(V); - } - - // See if we have a target specific builtin that needs to be lowered. - Value *V = 0; - - if (strcmp(TargetPrefix, "x86") == 0) - V = EmitX86BuiltinExpr(BuiltinID, E); - else if (strcmp(TargetPrefix, "ppc") == 0) - V = EmitPPCBuiltinExpr(BuiltinID, E); - - if (V) - return RValue::get(V); - - WarnUnsupported(E, "builtin function"); - - // Unknown builtin, for now just dump it out and return undef. - if (hasAggregateLLVMType(E->getType())) - return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType()))); - return RValue::get(UndefValue::get(ConvertType(E->getType()))); - } - case Builtin::BI__builtin___CFStringMakeConstantString: { - const Expr *Arg = E->getArg(0); - - while (1) { - if (const ParenExpr *PE = dyn_cast(Arg)) - Arg = PE->getSubExpr(); - else if (const ImplicitCastExpr *CE = dyn_cast(Arg)) - Arg = CE->getSubExpr(); - else - break; - } - - const StringLiteral *Literal = cast(Arg); - std::string S(Literal->getStrData(), Literal->getByteLength()); - - return RValue::get(CGM.GetAddrOfConstantCFString(S)); - } - case Builtin::BI__builtin_va_start: - case Builtin::BI__builtin_va_end: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); - const llvm::Type *DestType = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - if (ArgValue->getType() != DestType) - ArgValue = Builder.CreateBitCast(ArgValue, DestType, - ArgValue->getNameStart()); - - Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_start) ? - Intrinsic::vastart : Intrinsic::vaend; - return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue)); - } - case Builtin::BI__builtin_va_copy: { - // FIXME: This does not yet handle architectures where va_list is a struct. - Value *DstPtr = EmitScalarExpr(E->getArg(0)); - Value *SrcValue = EmitScalarExpr(E->getArg(1)); - - Value *SrcPtr = CreateTempAlloca(SrcValue->getType(), "dst_ptr"); - - // FIXME: Volatile - Builder.CreateStore(SrcValue, SrcPtr, false); - - const llvm::Type *Type = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - - DstPtr = Builder.CreateBitCast(DstPtr, Type); - SrcPtr = Builder.CreateBitCast(SrcPtr, Type); - Value *Args[] = { DstPtr, SrcPtr }; - return RValue::get(Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy), - &Args[0], &Args[2])); - } - case Builtin::BI__builtin_classify_type: { - APSInt Result(32); - if (!E->isBuiltinClassifyType(Result)) - assert(0 && "Expr not __builtin_classify_type!"); - return RValue::get(ConstantInt::get(Result)); - } - case Builtin::BI__builtin_constant_p: { - APSInt Result(32); - // FIXME: Analyze the parameter and check if it is a constant. - Result = 0; - return RValue::get(ConstantInt::get(Result)); - } - case Builtin::BI__builtin_abs: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); - - llvm::BinaryOperator *NegOp = - Builder.CreateNeg(ArgValue, (ArgValue->getName() + "neg").c_str()); - Value *CmpResult = - Builder.CreateICmpSGE(ArgValue, NegOp->getOperand(0), "abscond"); - Value *Result = - Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs"); - - return RValue::get(Result); - } - case Builtin::BI__builtin_ctz: - case Builtin::BI__builtin_ctzl: - case Builtin::BI__builtin_ctzll: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); - - const llvm::Type *ArgType = ArgValue->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1); - - const llvm::Type *ResultType = ConvertType(E->getType()); - Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); - if (Result->getType() != ResultType) - Result = Builder.CreateIntCast(Result, ResultType, "cast"); - return RValue::get(Result); - } - case Builtin::BI__builtin_expect: - return RValue::get(EmitScalarExpr(E->getArg(0))); - case Builtin::BI__builtin_bswap32: - case Builtin::BI__builtin_bswap64: { - Value *ArgValue = EmitScalarExpr(E->getArg(0)); - const llvm::Type *ArgType = ArgValue->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1); - return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); - } - case Builtin::BI__builtin_inff: { - APFloat f(APFloat::IEEEsingle, APFloat::fcInfinity, false); - return RValue::get(ConstantFP::get(llvm::Type::FloatTy, f)); - } - case Builtin::BI__builtin_huge_val: - case Builtin::BI__builtin_inf: - // FIXME: mapping long double onto double. - case Builtin::BI__builtin_infl: { - APFloat f(APFloat::IEEEdouble, APFloat::fcInfinity, false); - return RValue::get(ConstantFP::get(llvm::Type::DoubleTy, f)); - } - case Builtin::BI__builtin_isgreater: - case Builtin::BI__builtin_isgreaterequal: - case Builtin::BI__builtin_isless: - case Builtin::BI__builtin_islessequal: - case Builtin::BI__builtin_islessgreater: - case Builtin::BI__builtin_isunordered: { - // Ordered comparisons: we know the arguments to these are matching scalar - // floating point values. - Value *LHS = EmitScalarExpr(E->getArg(0)); - Value *RHS = EmitScalarExpr(E->getArg(1)); - - switch (BuiltinID) { - default: assert(0 && "Unknown ordered comparison"); - case Builtin::BI__builtin_isgreater: - LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp"); - break; - case Builtin::BI__builtin_isgreaterequal: - LHS = Builder.CreateFCmpOGE(LHS, RHS, "cmp"); - break; - case Builtin::BI__builtin_isless: - LHS = Builder.CreateFCmpOLT(LHS, RHS, "cmp"); - break; - case Builtin::BI__builtin_islessequal: - LHS = Builder.CreateFCmpOLE(LHS, RHS, "cmp"); - break; - case Builtin::BI__builtin_islessgreater: - LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp"); - break; - case Builtin::BI__builtin_isunordered: - LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp"); - break; - } - // ZExt bool to int type. - return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()), - "tmp")); - } - case Builtin::BI__builtin_alloca: - return RValue::get(Builder.CreateAlloca(llvm::Type::Int8Ty, - EmitScalarExpr(E->getArg(0)), - "tmp")); - } - return RValue::get(0); -} - -Value *CodeGenFunction::EmitX86BuiltinExpr(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))); - - switch (BuiltinID) { - default: return 0; - case X86::BI__builtin_ia32_mulps: - return Builder.CreateMul(Ops[0], Ops[1], "mulps"); - case X86::BI__builtin_ia32_pand: - return Builder.CreateAnd(Ops[0], Ops[1], "pand"); - case X86::BI__builtin_ia32_por: - return Builder.CreateAnd(Ops[0], Ops[1], "por"); - case X86::BI__builtin_ia32_pxor: - return Builder.CreateAnd(Ops[0], Ops[1], "pxor"); - case X86::BI__builtin_ia32_pandn: { - Ops[0] = Builder.CreateNot(Ops[0], "tmp"); - return Builder.CreateAnd(Ops[0], Ops[1], "pandn"); - } - case X86::BI__builtin_ia32_paddb: - case X86::BI__builtin_ia32_paddd: - case X86::BI__builtin_ia32_paddq: - case X86::BI__builtin_ia32_paddw: - case X86::BI__builtin_ia32_addps: - return Builder.CreateAdd(Ops[0], Ops[1], "add"); - case X86::BI__builtin_ia32_psubb: - case X86::BI__builtin_ia32_psubd: - case X86::BI__builtin_ia32_psubq: - case X86::BI__builtin_ia32_psubw: - case X86::BI__builtin_ia32_subps: - return Builder.CreateSub(Ops[0], Ops[1], "sub"); - case X86::BI__builtin_ia32_divps: - return Builder.CreateFDiv(Ops[0], Ops[1], "divps"); - case X86::BI__builtin_ia32_pmullw: - return Builder.CreateMul(Ops[0], Ops[1], "pmul"); - case X86::BI__builtin_ia32_punpckhbw: - return EmitShuffleVector(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15, - "punpckhbw"); - case X86::BI__builtin_ia32_punpckhwd: - return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "punpckhwd"); - case X86::BI__builtin_ia32_punpckhdq: - return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "punpckhdq"); - case X86::BI__builtin_ia32_punpcklbw: - return EmitShuffleVector(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11, - "punpcklbw"); - case X86::BI__builtin_ia32_punpcklwd: - return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "punpcklwd"); - case X86::BI__builtin_ia32_punpckldq: - return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "punpckldq"); - case X86::BI__builtin_ia32_pslldi: - case X86::BI__builtin_ia32_psllqi: - case X86::BI__builtin_ia32_psllwi: - case X86::BI__builtin_ia32_psradi: - case X86::BI__builtin_ia32_psrawi: - case X86::BI__builtin_ia32_psrldi: - case X86::BI__builtin_ia32_psrlqi: - case X86::BI__builtin_ia32_psrlwi: { - Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext"); - const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 1); - Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast"); - const char *name = 0; - Intrinsic::ID ID = Intrinsic::not_intrinsic; - - switch (BuiltinID) { - default: assert(0 && "Unsupported shift intrinsic!"); - case X86::BI__builtin_ia32_pslldi: - name = "pslldi"; - ID = Intrinsic::x86_mmx_psll_d; - break; - case X86::BI__builtin_ia32_psllqi: - name = "psllqi"; - ID = Intrinsic::x86_mmx_psll_q; - break; - case X86::BI__builtin_ia32_psllwi: - name = "psllwi"; - ID = Intrinsic::x86_mmx_psll_w; - break; - case X86::BI__builtin_ia32_psradi: - name = "psradi"; - ID = Intrinsic::x86_mmx_psra_d; - break; - case X86::BI__builtin_ia32_psrawi: - name = "psrawi"; - ID = Intrinsic::x86_mmx_psra_w; - break; - case X86::BI__builtin_ia32_psrldi: - name = "psrldi"; - ID = Intrinsic::x86_mmx_psrl_d; - break; - case X86::BI__builtin_ia32_psrlqi: - name = "psrlqi"; - ID = Intrinsic::x86_mmx_psrl_q; - break; - case X86::BI__builtin_ia32_psrlwi: - name = "psrlwi"; - ID = Intrinsic::x86_mmx_psrl_w; - break; - } - llvm::Function *F = CGM.getIntrinsic(ID); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); - } - case X86::BI__builtin_ia32_pshufd: { - unsigned i = cast(Ops[1])->getZExtValue(); - return EmitShuffleVector(Ops[0], Ops[0], - i & 0x3, (i & 0xc) >> 2, - (i & 0x30) >> 4, (i & 0xc0) >> 6, - "pshufd"); - } - case X86::BI__builtin_ia32_vec_init_v4hi: - case X86::BI__builtin_ia32_vec_init_v8qi: - case X86::BI__builtin_ia32_vec_init_v2si: - return EmitVector(&Ops[0], Ops.size()); - case X86::BI__builtin_ia32_vec_ext_v2si: - return Builder.CreateExtractElement(Ops[0], Ops[1], "result"); - case X86::BI__builtin_ia32_cmpordss: - case X86::BI__builtin_ia32_cmpunordss: - case X86::BI__builtin_ia32_cmpeqss: - case X86::BI__builtin_ia32_cmpltss: - case X86::BI__builtin_ia32_cmpless: - case X86::BI__builtin_ia32_cmpneqss: - case X86::BI__builtin_ia32_cmpnltss: - case X86::BI__builtin_ia32_cmpnless: { - unsigned i = 0; - const char *name = 0; - switch (BuiltinID) { - default: assert(0 && "Unknown compare builtin!"); - case X86::BI__builtin_ia32_cmpeqss: - i = 0; - name = "cmpeqss"; - break; - case X86::BI__builtin_ia32_cmpltss: - i = 1; - name = "cmpltss"; - break; - case X86::BI__builtin_ia32_cmpless: - i = 2; - name = "cmpless"; - break; - case X86::BI__builtin_ia32_cmpunordss: - i = 3; - name = "cmpunordss"; - break; - case X86::BI__builtin_ia32_cmpneqss: - i = 4; - name = "cmpneqss"; - break; - case X86::BI__builtin_ia32_cmpnltss: - i = 5; - name = "cmpntlss"; - break; - case X86::BI__builtin_ia32_cmpnless: - i = 6; - name = "cmpnless"; - break; - case X86::BI__builtin_ia32_cmpordss: - i = 7; - name = "cmpordss"; - break; - } - - Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i)); - llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); - } - case X86::BI__builtin_ia32_cmpordps: - case X86::BI__builtin_ia32_cmpunordps: - case X86::BI__builtin_ia32_cmpeqps: - case X86::BI__builtin_ia32_cmpltps: - case X86::BI__builtin_ia32_cmpleps: - case X86::BI__builtin_ia32_cmpneqps: - case X86::BI__builtin_ia32_cmpngtps: - case X86::BI__builtin_ia32_cmpnltps: - case X86::BI__builtin_ia32_cmpgtps: - case X86::BI__builtin_ia32_cmpgeps: - case X86::BI__builtin_ia32_cmpngeps: - case X86::BI__builtin_ia32_cmpnleps: { - unsigned i = 0; - const char *name = 0; - bool ShouldSwap = false; - switch (BuiltinID) { - default: assert(0 && "Unknown compare builtin!"); - case X86::BI__builtin_ia32_cmpeqps: i = 0; name = "cmpeqps"; break; - case X86::BI__builtin_ia32_cmpltps: i = 1; name = "cmpltps"; break; - case X86::BI__builtin_ia32_cmpleps: i = 2; name = "cmpleps"; break; - case X86::BI__builtin_ia32_cmpunordps: i = 3; name = "cmpunordps"; break; - case X86::BI__builtin_ia32_cmpneqps: i = 4; name = "cmpneqps"; break; - case X86::BI__builtin_ia32_cmpnltps: i = 5; name = "cmpntlps"; break; - case X86::BI__builtin_ia32_cmpnleps: i = 6; name = "cmpnleps"; break; - case X86::BI__builtin_ia32_cmpordps: i = 7; name = "cmpordps"; break; - case X86::BI__builtin_ia32_cmpgtps: - ShouldSwap = true; - i = 1; - name = "cmpgtps"; - break; - case X86::BI__builtin_ia32_cmpgeps: - i = 2; - name = "cmpgeps"; - ShouldSwap = true; - break; - case X86::BI__builtin_ia32_cmpngtps: - i = 5; - name = "cmpngtps"; - ShouldSwap = true; - break; - case X86::BI__builtin_ia32_cmpngeps: - i = 6; - name = "cmpngeps"; - ShouldSwap = true; - break; - } - - if (ShouldSwap) - std::swap(Ops[0], Ops[1]); - - Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i)); - llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); - } - case X86::BI__builtin_ia32_movss: - return EmitShuffleVector(Ops[0], Ops[1], 4, 1, 2, 3, "movss"); - case X86::BI__builtin_ia32_shufps: - unsigned i = cast(Ops[2])->getZExtValue(); - return EmitShuffleVector(Ops[0], Ops[1], - i & 0x3, (i & 0xc) >> 2, - ((i & 0x30) >> 4) + 4, - ((i & 0x60) >> 6) + 4, "shufps"); - } -} - -Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, - const CallExpr *E) { - switch (BuiltinID) { - default: return 0; - } -} diff --git a/clang/CodeGen/CGDecl.cpp b/clang/CodeGen/CGDecl.cpp deleted file mode 100644 index c80cecc76ee..00000000000 --- a/clang/CodeGen/CGDecl.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Decl nodes as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/AST.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Type.h" -using namespace clang; -using namespace CodeGen; - - -void CodeGenFunction::EmitDecl(const Decl &D) { - switch (D.getKind()) { - default: assert(0 && "Unknown decl kind!"); - case Decl::FileVar: - assert(0 && "Should not see file-scope variables inside a function!"); - case Decl::ParmVar: - assert(0 && "Parmdecls should not be in declstmts!"); - case Decl::Typedef: // typedef int X; - case Decl::Function: // void X(); - case Decl::Struct: // struct X; - case Decl::Union: // union X; - case Decl::Class: // class X; - case Decl::Enum: // enum X; - // None of these decls require codegen support. - return; - - case Decl::BlockVar: - return EmitBlockVarDecl(cast(D)); - case Decl::EnumConstant: - return EmitEnumConstantDecl(cast(D)); - } -} - -void CodeGenFunction::EmitEnumConstantDecl(const EnumConstantDecl &D) { - assert(0 && "FIXME: Enum constant decls not implemented yet!"); -} - -/// EmitBlockVarDecl - This method handles emission of any variable declaration -/// inside a function, including static vars etc. -void CodeGenFunction::EmitBlockVarDecl(const BlockVarDecl &D) { - switch (D.getStorageClass()) { - case VarDecl::Static: - return EmitStaticBlockVarDecl(D); - case VarDecl::Extern: - // Don't emit it now, allow it to be emitted lazily on its first use. - return; - default: - assert((D.getStorageClass() == VarDecl::None || - D.getStorageClass() == VarDecl::Auto || - D.getStorageClass() == VarDecl::Register) && - "Unknown storage class"); - return EmitLocalBlockVarDecl(D); - } -} - -void CodeGenFunction::EmitStaticBlockVarDecl(const BlockVarDecl &D) { - QualType Ty = D.getCanonicalType(); - assert(Ty->isConstantSizeType() && "VLAs can't be static"); - - llvm::Value *&DMEntry = LocalDeclMap[&D]; - assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - - const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); - llvm::Constant *Init = 0; - if (D.getInit() == 0) { - Init = llvm::Constant::getNullValue(LTy); - } else { - Init = CGM.EmitConstantExpr(D.getInit(), this); - } - - assert(Init && "Unable to create initialiser for static decl"); - - std::string ContextName; - if (CurFuncDecl) - ContextName = CurFuncDecl->getName(); - else - assert(0 && "Unknown context for block var decl"); // FIXME Handle objc. - - DMEntry = - new llvm::GlobalVariable(LTy, false, - llvm::GlobalValue::InternalLinkage, - Init, ContextName + "." + D.getName(), - &CGM.getModule(), 0, - Ty.getAddressSpace()); - -} - -/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a -/// variable declaration with auto, register, or no storage class specifier. -/// These turn into simple stack objects. -void CodeGenFunction::EmitLocalBlockVarDecl(const BlockVarDecl &D) { - QualType Ty = D.getCanonicalType(); - - llvm::Value *DeclPtr; - if (Ty->isConstantSizeType()) { - // A normal fixed sized variable becomes an alloca in the entry block. - const llvm::Type *LTy = ConvertType(Ty); - // TODO: Alignment - DeclPtr = CreateTempAlloca(LTy, D.getName()); - } else { - // TODO: Create a dynamic alloca. - assert(0 && "FIXME: Local VLAs not implemented yet"); - } - - llvm::Value *&DMEntry = LocalDeclMap[&D]; - assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - DMEntry = DeclPtr; - - // If this local has an initializer, emit it now. - if (const Expr *Init = D.getInit()) { - if (!hasAggregateLLVMType(Init->getType())) { - llvm::Value *V = EmitScalarExpr(Init); - Builder.CreateStore(V, DeclPtr, D.getType().isVolatileQualified()); - } else if (Init->getType()->isComplexType()) { - EmitComplexExprIntoAddr(Init, DeclPtr, D.getType().isVolatileQualified()); - } else { - EmitAggExpr(Init, DeclPtr, D.getType().isVolatileQualified()); - } - } -} - -/// Emit an alloca for the specified parameter and set up LocalDeclMap. -void CodeGenFunction::EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg) { - QualType Ty = D.getCanonicalType(); - - llvm::Value *DeclPtr; - if (!Ty->isConstantSizeType()) { - // Variable sized values always are passed by-reference. - DeclPtr = Arg; - } else { - // A fixed sized first class variable becomes an alloca in the entry block. - const llvm::Type *LTy = ConvertType(Ty); - if (LTy->isFirstClassType()) { - // TODO: Alignment - DeclPtr = new llvm::AllocaInst(LTy, 0, std::string(D.getName())+".addr", - AllocaInsertPt); - - // Store the initial value into the alloca. - Builder.CreateStore(Arg, DeclPtr); - } else { - // Otherwise, if this is an aggregate, just use the input pointer. - DeclPtr = Arg; - } - Arg->setName(D.getName()); - } - - llvm::Value *&DMEntry = LocalDeclMap[&D]; - assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - DMEntry = DeclPtr; -} - diff --git a/clang/CodeGen/CGExpr.cpp b/clang/CodeGen/CGExpr.cpp deleted file mode 100644 index 932a5c5da8b..00000000000 --- a/clang/CodeGen/CGExpr.cpp +++ /dev/null @@ -1,615 +0,0 @@ -//===--- CGExpr.cpp - Emit LLVM Code from Expressions ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Expr nodes as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/AST.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Support/MathExtras.h" -using namespace clang; -using namespace CodeGen; - -//===--------------------------------------------------------------------===// -// Miscellaneous Helper Methods -//===--------------------------------------------------------------------===// - -/// CreateTempAlloca - This creates a alloca and inserts it into the entry -/// block. -llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, - const char *Name) { - return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); -} - -/// EvaluateExprAsBool - Perform the usual unary conversions on the specified -/// expression and compare the result against zero, returning an Int1Ty value. -llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { - QualType BoolTy = getContext().BoolTy; - if (!E->getType()->isComplexType()) - return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); - - return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy); -} - -/// EmitAnyExpr - Emit code to compute the specified expression which can have -/// any type. The result is returned as an RValue struct. If this is an -/// aggregate expression, the aggloc/agglocvolatile arguments indicate where -/// the result should be returned. -RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc, - bool isAggLocVolatile) { - if (!hasAggregateLLVMType(E->getType())) - return RValue::get(EmitScalarExpr(E)); - else if (E->getType()->isComplexType()) - return RValue::getComplex(EmitComplexExpr(E)); - - EmitAggExpr(E, AggLoc, isAggLocVolatile); - return RValue::getAggregate(AggLoc); -} - - -//===----------------------------------------------------------------------===// -// LValue Expression Emission -//===----------------------------------------------------------------------===// - -/// EmitLValue - Emit code to compute a designator that specifies the location -/// of the expression. -/// -/// This can return one of two things: a simple address or a bitfield -/// reference. In either case, the LLVM Value* in the LValue structure is -/// guaranteed to be an LLVM pointer type. -/// -/// If this returns a bitfield reference, nothing about the pointee type of -/// the LLVM value is known: For example, it may not be a pointer to an -/// integer. -/// -/// If this returns a normal address, and if the lvalue's C type is fixed -/// size, this method guarantees that the returned pointer type will point to -/// an LLVM type of the same size of the lvalue's type. If the lvalue has a -/// variable length type, this is not possible. -/// -LValue CodeGenFunction::EmitLValue(const Expr *E) { - switch (E->getStmtClass()) { - default: { - WarnUnsupported(E, "l-value expression"); - llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); - return LValue::MakeAddr(llvm::UndefValue::get(Ty)); - } - - case Expr::CallExprClass: return EmitCallExprLValue(cast(E)); - case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast(E)); - case Expr::ParenExprClass:return EmitLValue(cast(E)->getSubExpr()); - case Expr::PreDefinedExprClass: - return EmitPreDefinedLValue(cast(E)); - case Expr::StringLiteralClass: - return EmitStringLiteralLValue(cast(E)); - - case Expr::UnaryOperatorClass: - return EmitUnaryOpLValue(cast(E)); - case Expr::ArraySubscriptExprClass: - return EmitArraySubscriptExpr(cast(E)); - case Expr::OCUVectorElementExprClass: - return EmitOCUVectorElementExpr(cast(E)); - case Expr::MemberExprClass: return EmitMemberExpr(cast(E)); - } -} - -/// EmitLoadOfLValue - Given an expression that represents a value lvalue, -/// this method emits the address of the lvalue, then loads the result as an -/// rvalue, returning the rvalue. -RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { - if (LV.isSimple()) { - llvm::Value *Ptr = LV.getAddress(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - - // Simple scalar l-value. - if (EltTy->isFirstClassType()) { - llvm::Value *V = Builder.CreateLoad(Ptr, "tmp"); - - // Bool can have different representation in memory than in registers. - if (ExprType->isBooleanType()) { - if (V->getType() != llvm::Type::Int1Ty) - V = Builder.CreateTrunc(V, llvm::Type::Int1Ty, "tobool"); - } - - return RValue::get(V); - } - - assert(ExprType->isFunctionType() && "Unknown scalar value"); - return RValue::get(Ptr); - } - - if (LV.isVectorElt()) { - llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(), "tmp"); - return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(), - "vecext")); - } - - // If this is a reference to a subset of the elements of a vector, either - // shuffle the input or extract/insert them as appropriate. - if (LV.isOCUVectorElt()) - return EmitLoadOfOCUElementLValue(LV, ExprType); - - if (LV.isBitfield()) - return EmitLoadOfBitfieldLValue(LV, ExprType); - - assert(0 && "Unknown LValue type!"); - //an invalid RValue, but the assert will - //ensure that this point is never reached - return RValue(); -} - -RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, - QualType ExprType) { - llvm::Value *Ptr = LV.getBitfieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = EltTy->getPrimitiveSizeInBits(); - unsigned short BitfieldSize = LV.getBitfieldSize(); - unsigned short EndBit = LV.getBitfieldStartBit() + BitfieldSize; - - llvm::Value *V = Builder.CreateLoad(Ptr, "tmp"); - - llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - EndBit); - V = Builder.CreateShl(V, ShAmt, "tmp"); - - ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - BitfieldSize); - V = LV.isBitfieldSigned() ? - Builder.CreateAShr(V, ShAmt, "tmp") : - Builder.CreateLShr(V, ShAmt, "tmp"); - return RValue::get(V); -} - -// If this is a reference to a subset of the elements of a vector, either -// shuffle the input or extract/insert them as appropriate. -RValue CodeGenFunction::EmitLoadOfOCUElementLValue(LValue LV, - QualType ExprType) { - llvm::Value *Vec = Builder.CreateLoad(LV.getOCUVectorAddr(), "tmp"); - - unsigned EncFields = LV.getOCUVectorElts(); - - // If the result of the expression is a non-vector type, we must be - // extracting a single element. Just codegen as an extractelement. - const VectorType *ExprVT = ExprType->getAsVectorType(); - if (!ExprVT) { - unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields); - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); - return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp")); - } - - // If the source and destination have the same number of elements, use a - // vector shuffle instead of insert/extracts. - unsigned NumResultElts = ExprVT->getNumElements(); - unsigned NumSourceElts = - cast(Vec->getType())->getNumElements(); - - if (NumResultElts == NumSourceElts) { - llvm::SmallVector Mask; - for (unsigned i = 0; i != NumResultElts; ++i) { - unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields); - Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); - } - - llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); - Vec = Builder.CreateShuffleVector(Vec, - llvm::UndefValue::get(Vec->getType()), - MaskV, "tmp"); - return RValue::get(Vec); - } - - // Start out with an undef of the result type. - llvm::Value *Result = llvm::UndefValue::get(ConvertType(ExprType)); - - // Extract/Insert each element of the result. - for (unsigned i = 0; i != NumResultElts; ++i) { - unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields); - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); - Elt = Builder.CreateExtractElement(Vec, Elt, "tmp"); - - llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - Result = Builder.CreateInsertElement(Result, Elt, OutIdx, "tmp"); - } - - return RValue::get(Result); -} - - - -/// EmitStoreThroughLValue - Store the specified rvalue into the specified -/// lvalue, where both are guaranteed to the have the same type, and that type -/// is 'Ty'. -void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, - QualType Ty) { - if (!Dst.isSimple()) { - if (Dst.isVectorElt()) { - // Read/modify/write the vector, inserting the new element. - // FIXME: Volatility. - llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(), "tmp"); - Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), - Dst.getVectorIdx(), "vecins"); - Builder.CreateStore(Vec, Dst.getVectorAddr()); - return; - } - - // If this is an update of elements of a vector, insert them as appropriate. - if (Dst.isOCUVectorElt()) - return EmitStoreThroughOCUComponentLValue(Src, Dst, Ty); - - if (Dst.isBitfield()) - return EmitStoreThroughBitfieldLValue(Src, Dst, Ty); - - assert(0 && "Unknown LValue type"); - } - - llvm::Value *DstAddr = Dst.getAddress(); - assert(Src.isScalar() && "Can't emit an agg store with this method"); - // FIXME: Handle volatility etc. - const llvm::Type *SrcTy = Src.getScalarVal()->getType(); - const llvm::PointerType *DstPtr = cast(DstAddr->getType()); - const llvm::Type *AddrTy = DstPtr->getElementType(); - unsigned AS = DstPtr->getAddressSpace(); - - if (AddrTy != SrcTy) - DstAddr = Builder.CreateBitCast(DstAddr, - llvm::PointerType::get(SrcTy, AS), - "storetmp"); - Builder.CreateStore(Src.getScalarVal(), DstAddr); -} - -void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, - QualType Ty) { - unsigned short StartBit = Dst.getBitfieldStartBit(); - unsigned short BitfieldSize = Dst.getBitfieldSize(); - llvm::Value *Ptr = Dst.getBitfieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = EltTy->getPrimitiveSizeInBits(); - - llvm::Value *NewVal = Src.getScalarVal(); - llvm::Value *OldVal = Builder.CreateLoad(Ptr, "tmp"); - - llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, StartBit); - NewVal = Builder.CreateShl(NewVal, ShAmt, "tmp"); - - llvm::Constant *Mask = llvm::ConstantInt::get( - llvm::APInt::getBitsSet(EltTySize, StartBit, - StartBit + BitfieldSize)); - - // Mask out any bits that shouldn't be set in the result. - NewVal = Builder.CreateAnd(NewVal, Mask, "tmp"); - - // Next, mask out the bits this bit-field should include from the old value. - Mask = llvm::ConstantExpr::getNot(Mask); - OldVal = Builder.CreateAnd(OldVal, Mask, "tmp"); - - // Finally, merge the two together and store it. - NewVal = Builder.CreateOr(OldVal, NewVal, "tmp"); - - Builder.CreateStore(NewVal, Ptr); -} - -void CodeGenFunction::EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, - QualType Ty) { - // This access turns into a read/modify/write of the vector. Load the input - // value now. - llvm::Value *Vec = Builder.CreateLoad(Dst.getOCUVectorAddr(), "tmp"); - // FIXME: Volatility. - unsigned EncFields = Dst.getOCUVectorElts(); - - llvm::Value *SrcVal = Src.getScalarVal(); - - if (const VectorType *VTy = Ty->getAsVectorType()) { - unsigned NumSrcElts = VTy->getNumElements(); - - // Extract/Insert each element. - for (unsigned i = 0; i != NumSrcElts; ++i) { - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp"); - - unsigned Idx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields); - llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx); - Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp"); - } - } else { - // If the Src is a scalar (not a vector) it must be updating one element. - unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields); - llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); - Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); - } - - Builder.CreateStore(Vec, Dst.getOCUVectorAddr()); -} - - -LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { - const ValueDecl *D = E->getDecl(); - if (isa(D) || isa(D)) { - const VarDecl *VD = cast(D); - if (VD->getStorageClass() == VarDecl::Extern) - return LValue::MakeAddr(CGM.GetAddrOfGlobalVar(VD, false)); - else { - llvm::Value *V = LocalDeclMap[D]; - assert(V && "BlockVarDecl not entered in LocalDeclMap?"); - return LValue::MakeAddr(V); - } - } else if (const FunctionDecl *FD = dyn_cast(D)) { - return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false)); - } else if (const FileVarDecl *FVD = dyn_cast(D)) { - return LValue::MakeAddr(CGM.GetAddrOfGlobalVar(FVD, false)); - } - assert(0 && "Unimp declref"); - //an invalid LValue, but the assert will - //ensure that this point is never reached. - return LValue(); -} - -LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { - // __extension__ doesn't affect lvalue-ness. - if (E->getOpcode() == UnaryOperator::Extension) - return EmitLValue(E->getSubExpr()); - - switch (E->getOpcode()) { - default: assert(0 && "Unknown unary operator lvalue!"); - case UnaryOperator::Deref: - return LValue::MakeAddr(EmitScalarExpr(E->getSubExpr())); - case UnaryOperator::Real: - case UnaryOperator::Imag: - LValue LV = EmitLValue(E->getSubExpr()); - - llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, - E->getOpcode() == UnaryOperator::Imag); - llvm::Value *Ops[] = {Zero, Idx}; - return LValue::MakeAddr(Builder.CreateGEP(LV.getAddress(), Ops, Ops+2, - "idx")); - } -} - -LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { - assert(!E->isWide() && "FIXME: Wide strings not supported yet!"); - const char *StrData = E->getStrData(); - unsigned Len = E->getByteLength(); - std::string StringLiteral(StrData, StrData+Len); - return LValue::MakeAddr(CGM.GetAddrOfConstantString(StringLiteral)); -} - -LValue CodeGenFunction::EmitPreDefinedLValue(const PreDefinedExpr *E) { - std::string FunctionName(CurFuncDecl->getName()); - std::string GlobalVarName; - - switch (E->getIdentType()) { - default: - assert(0 && "unknown pre-defined ident type"); - case PreDefinedExpr::Func: - GlobalVarName = "__func__."; - break; - case PreDefinedExpr::Function: - GlobalVarName = "__FUNCTION__."; - break; - case PreDefinedExpr::PrettyFunction: - // FIXME:: Demangle C++ method names - GlobalVarName = "__PRETTY_FUNCTION__."; - break; - } - - GlobalVarName += CurFuncDecl->getName(); - - // FIXME: Can cache/reuse these within the module. - llvm::Constant *C=llvm::ConstantArray::get(FunctionName); - - // Create a global variable for this. - C = new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, GlobalVarName, CurFn->getParent()); - return LValue::MakeAddr(C); -} - -LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { - // The index must always be an integer, which is not an aggregate. Emit it. - llvm::Value *Idx = EmitScalarExpr(E->getIdx()); - - // If the base is a vector type, then we are forming a vector element lvalue - // with this subscript. - if (E->getLHS()->getType()->isVectorType()) { - // Emit the vector as an lvalue to get its address. - LValue LHS = EmitLValue(E->getLHS()); - assert(LHS.isSimple() && "Can only subscript lvalue vectors here!"); - // FIXME: This should properly sign/zero/extend or truncate Idx to i32. - return LValue::MakeVectorElt(LHS.getAddress(), Idx); - } - - // The base must be a pointer, which is not an aggregate. Emit it. - llvm::Value *Base = EmitScalarExpr(E->getBase()); - - // Extend or truncate the index type to 32 or 64-bits. - QualType IdxTy = E->getIdx()->getType(); - bool IdxSigned = IdxTy->isSignedIntegerType(); - unsigned IdxBitwidth = cast(Idx->getType())->getBitWidth(); - if (IdxBitwidth != LLVMPointerWidth) - Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth), - IdxSigned, "idxprom"); - - // We know that the pointer points to a type of the correct size, unless the - // size is a VLA. - if (!E->getType()->isConstantSizeType()) - assert(0 && "VLA idx not implemented"); - return LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx")); -} - -LValue CodeGenFunction:: -EmitOCUVectorElementExpr(const OCUVectorElementExpr *E) { - // Emit the base vector as an l-value. - LValue Base = EmitLValue(E->getBase()); - assert(Base.isSimple() && "Can only subscript lvalue vectors here!"); - - return LValue::MakeOCUVectorElt(Base.getAddress(), - E->getEncodedElementAccess()); -} - -LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { - bool isUnion = false; - Expr *BaseExpr = E->getBase(); - llvm::Value *BaseValue = NULL; - - // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. - if (E->isArrow()) { - BaseValue = EmitScalarExpr(BaseExpr); - const PointerType *PTy = - cast(BaseExpr->getType().getCanonicalType()); - if (PTy->getPointeeType()->isUnionType()) - isUnion = true; - } - else { - LValue BaseLV = EmitLValue(BaseExpr); - // FIXME: this isn't right for bitfields. - BaseValue = BaseLV.getAddress(); - if (BaseExpr->getType()->isUnionType()) - isUnion = true; - } - - FieldDecl *Field = E->getMemberDecl(); - return EmitLValueForField(BaseValue, Field, isUnion); -} - -LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, - FieldDecl* Field, - bool isUnion) -{ - llvm::Value *V; - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); - - if (Field->isBitField()) { - const llvm::Type * FieldTy = ConvertType(Field->getType()); - const llvm::PointerType * BaseTy = - cast(BaseValue->getType()); - unsigned AS = BaseTy->getAddressSpace(); - BaseValue = Builder.CreateBitCast(BaseValue, - llvm::PointerType::get(FieldTy, AS), - "tmp"); - V = Builder.CreateGEP(BaseValue, - llvm::ConstantInt::get(llvm::Type::Int32Ty, idx), - "tmp"); - } else { - llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty), - llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) }; - V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp"); - } - // Match union field type. - if (isUnion) { - const llvm::Type * FieldTy = ConvertType(Field->getType()); - const llvm::PointerType * BaseTy = - cast(BaseValue->getType()); - if (FieldTy != BaseTy->getElementType()) { - unsigned AS = BaseTy->getAddressSpace(); - V = Builder.CreateBitCast(V, - llvm::PointerType::get(FieldTy, AS), - "tmp"); - } - } - - if (Field->isBitField()) { - CodeGenTypes::BitFieldInfo bitFieldInfo = - CGM.getTypes().getBitFieldInfo(Field); - return LValue::MakeBitfield(V, bitFieldInfo.Begin, bitFieldInfo.Size, - Field->getType()->isSignedIntegerType()); - } else - return LValue::MakeAddr(V); -} - -//===--------------------------------------------------------------------===// -// Expression Emission -//===--------------------------------------------------------------------===// - - -RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { - if (const ImplicitCastExpr *IcExpr = - dyn_cast(E->getCallee())) - if (const DeclRefExpr *DRExpr = - dyn_cast(IcExpr->getSubExpr())) - if (const FunctionDecl *FDecl = - dyn_cast(DRExpr->getDecl())) - if (unsigned builtinID = FDecl->getIdentifier()->getBuiltinID()) - return EmitBuiltinExpr(builtinID, E); - - llvm::Value *Callee = EmitScalarExpr(E->getCallee()); - return EmitCallExpr(Callee, E->getCallee()->getType(), - E->arg_begin(), E->getNumArgs()); -} - -RValue CodeGenFunction::EmitCallExpr(Expr *FnExpr, Expr *const *Args, - unsigned NumArgs) { - llvm::Value *Callee = EmitScalarExpr(FnExpr); - return EmitCallExpr(Callee, FnExpr->getType(), Args, NumArgs); -} - -LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { - // Can only get l-value for call expression returning aggregate type - RValue RV = EmitCallExpr(E); - return LValue::MakeAddr(RV.getAggregateAddr()); -} - -RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType, - Expr *const *ArgExprs, unsigned NumArgs) { - // The callee type will always be a pointer to function type, get the function - // type. - FnType = cast(FnType.getCanonicalType())->getPointeeType(); - QualType ResultType = cast(FnType)->getResultType(); - - llvm::SmallVector Args; - - // Handle struct-return functions by passing a pointer to the location that - // we would like to return into. - if (hasAggregateLLVMType(ResultType)) { - // Create a temporary alloca to hold the result of the call. :( - Args.push_back(CreateTempAlloca(ConvertType(ResultType))); - // FIXME: set the stret attribute on the argument. - } - - for (unsigned i = 0, e = NumArgs; i != e; ++i) { - QualType ArgTy = ArgExprs[i]->getType(); - - if (!hasAggregateLLVMType(ArgTy)) { - // Scalar argument is passed by-value. - Args.push_back(EmitScalarExpr(ArgExprs[i])); - } else if (ArgTy->isComplexType()) { - // Make a temporary alloca to pass the argument. - llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); - EmitComplexExprIntoAddr(ArgExprs[i], DestMem, false); - Args.push_back(DestMem); - } else { - llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); - EmitAggExpr(ArgExprs[i], DestMem, false); - Args.push_back(DestMem); - } - } - - llvm::CallInst *CI = Builder.CreateCall(Callee,&Args[0],&Args[0]+Args.size()); - if (const llvm::Function *F = dyn_cast(Callee)) - CI->setCallingConv(F->getCallingConv()); - if (CI->getType() != llvm::Type::VoidTy) - CI->setName("call"); - else if (ResultType->isComplexType()) - return RValue::getComplex(LoadComplexFromAddr(Args[0], false)); - else if (hasAggregateLLVMType(ResultType)) - // Struct return. - return RValue::getAggregate(Args[0]); - else { - // void return. - assert(ResultType->isVoidType() && "Should only have a void expr here"); - CI = 0; - } - - return RValue::get(CI); -} diff --git a/clang/CodeGen/CGExprAgg.cpp b/clang/CodeGen/CGExprAgg.cpp deleted file mode 100644 index 325ac2109eb..00000000000 --- a/clang/CodeGen/CGExprAgg.cpp +++ /dev/null @@ -1,337 +0,0 @@ -//===--- CGExprAgg.cpp - Emit LLVM Code from Aggregate Expressions --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Aggregate Expr nodes as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/AST.h" -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Support/Compiler.h" -using namespace clang; -using namespace CodeGen; - -//===----------------------------------------------------------------------===// -// Aggregate Expression Emitter -//===----------------------------------------------------------------------===// - -namespace { -class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor { - CodeGenFunction &CGF; - llvm::LLVMFoldingBuilder &Builder; - llvm::Value *DestPtr; - bool VolatileDest; -public: - AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool volatileDest) - : CGF(cgf), Builder(CGF.Builder), - DestPtr(destPtr), VolatileDest(volatileDest) { - } - - //===--------------------------------------------------------------------===// - // Utilities - //===--------------------------------------------------------------------===// - - /// EmitAggLoadOfLValue - Given an expression with aggregate type that - /// represents a value lvalue, this method emits the address of the lvalue, - /// then loads the result into DestPtr. - void EmitAggLoadOfLValue(const Expr *E); - - void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType EltTy); - - void EmitAggregateClear(llvm::Value *DestPtr, QualType Ty); - - void EmitNonConstInit(InitListExpr *E); - - //===--------------------------------------------------------------------===// - // Visitor Methods - //===--------------------------------------------------------------------===// - - void VisitStmt(Stmt *S) { - CGF.WarnUnsupported(S, "aggregate expression"); - } - void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); } - - // l-values. - void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); } - void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); } - void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); } - void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); } - - void VisitArraySubscriptExpr(ArraySubscriptExpr *E) { - EmitAggLoadOfLValue(E); - } - - // Operators. - // case Expr::UnaryOperatorClass: - // case Expr::CastExprClass: - void VisitImplicitCastExpr(ImplicitCastExpr *E); - void VisitCallExpr(const CallExpr *E); - void VisitStmtExpr(const StmtExpr *E); - void VisitBinaryOperator(const BinaryOperator *BO); - void VisitBinAssign(const BinaryOperator *E); - void VisitOverloadExpr(const OverloadExpr *E); - - - void VisitConditionalOperator(const ConditionalOperator *CO); - void VisitInitListExpr(InitListExpr *E); - // case Expr::ChooseExprClass: - -}; -} // end anonymous namespace. - -//===----------------------------------------------------------------------===// -// Utilities -//===----------------------------------------------------------------------===// - -void AggExprEmitter::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) { - assert(!Ty->isComplexType() && "Shouldn't happen for complex"); - - // Aggregate assignment turns into llvm.memset. - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - if (DestPtr->getType() != BP) - DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); - - // Get size and alignment info for this aggregate. - std::pair TypeInfo = CGF.getContext().getTypeInfo(Ty); - - // FIXME: Handle variable sized types. - const llvm::Type *IntPtr = llvm::IntegerType::get(CGF.LLVMPointerWidth); - - llvm::Value *MemSetOps[4] = { - DestPtr, - llvm::ConstantInt::getNullValue(llvm::Type::Int8Ty), - // TypeInfo.first describes size in bits. - llvm::ConstantInt::get(IntPtr, TypeInfo.first/8), - llvm::ConstantInt::get(llvm::Type::Int32Ty, TypeInfo.second/8) - }; - - Builder.CreateCall(CGF.CGM.getMemSetFn(), MemSetOps, MemSetOps+4); -} - -void AggExprEmitter::EmitAggregateCopy(llvm::Value *DestPtr, - llvm::Value *SrcPtr, QualType Ty) { - assert(!Ty->isComplexType() && "Shouldn't happen for complex"); - - // Aggregate assignment turns into llvm.memcpy. - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - if (DestPtr->getType() != BP) - DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); - if (SrcPtr->getType() != BP) - SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); - - // Get size and alignment info for this aggregate. - std::pair TypeInfo = CGF.getContext().getTypeInfo(Ty); - - // FIXME: Handle variable sized types. - const llvm::Type *IntPtr = llvm::IntegerType::get(CGF.LLVMPointerWidth); - - llvm::Value *MemCpyOps[4] = { - DestPtr, SrcPtr, - // TypeInfo.first describes size in bits. - llvm::ConstantInt::get(IntPtr, TypeInfo.first/8), - llvm::ConstantInt::get(llvm::Type::Int32Ty, TypeInfo.second/8) - }; - - Builder.CreateCall(CGF.CGM.getMemCpyFn(), MemCpyOps, MemCpyOps+4); -} - - -/// EmitAggLoadOfLValue - Given an expression with aggregate type that -/// represents a value lvalue, this method emits the address of the lvalue, -/// then loads the result into DestPtr. -void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) { - LValue LV = CGF.EmitLValue(E); - assert(LV.isSimple() && "Can't have aggregate bitfield, vector, etc"); - llvm::Value *SrcPtr = LV.getAddress(); - - // If the result is ignored, don't copy from the value. - if (DestPtr == 0) - // FIXME: If the source is volatile, we must read from it. - return; - - EmitAggregateCopy(DestPtr, SrcPtr, E->getType()); -} - -//===----------------------------------------------------------------------===// -// Visitor Methods -//===----------------------------------------------------------------------===// - -void AggExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *E) -{ - QualType STy = E->getSubExpr()->getType().getCanonicalType(); - QualType Ty = E->getType().getCanonicalType(); - - assert(CGF.getContext().typesAreCompatible( - STy.getUnqualifiedType(), Ty.getUnqualifiedType()) - && "Implicit cast types must be compatible"); - - Visit(E->getSubExpr()); -} - -void AggExprEmitter::VisitCallExpr(const CallExpr *E) -{ - RValue RV = CGF.EmitCallExpr(E); - assert(RV.isAggregate() && "Return value must be aggregate value!"); - - // If the result is ignored, don't copy from the value. - if (DestPtr == 0) - // FIXME: If the source is volatile, we must read from it. - return; - - EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType()); -} - -void AggExprEmitter::VisitOverloadExpr(const OverloadExpr *E) -{ - RValue RV = CGF.EmitCallExpr(E->getFn(), E->arg_begin(), - E->getNumArgs(CGF.getContext())); - assert(RV.isAggregate() && "Return value must be aggregate value!"); - - // If the result is ignored, don't copy from the value. - if (DestPtr == 0) - // FIXME: If the source is volatile, we must read from it. - return; - - EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType()); -} - -void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { - CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest); -} - -void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { - CGF.WarnUnsupported(E, "aggregate binary expression"); -} - -void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { - // For an assignment to work, the value on the right has - // to be compatible with the value on the left. - assert(CGF.getContext().typesAreCompatible( - E->getLHS()->getType().getUnqualifiedType(), - E->getRHS()->getType().getUnqualifiedType()) - && "Invalid assignment"); - LValue LHS = CGF.EmitLValue(E->getLHS()); - - // Codegen the RHS so that it stores directly into the LHS. - CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), false /*FIXME: VOLATILE LHS*/); - - if (DestPtr == 0) - return; - - // If the result of the assignment is used, copy the RHS there also. - EmitAggregateCopy(DestPtr, LHS.getAddress(), E->getType()); -} - -void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { - llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?"); - llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:"); - llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont"); - - llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); - Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); - - CGF.EmitBlock(LHSBlock); - - // Handle the GNU extension for missing LHS. - assert(E->getLHS() && "Must have LHS for aggregate value"); - - Visit(E->getLHS()); - Builder.CreateBr(ContBlock); - LHSBlock = Builder.GetInsertBlock(); - - CGF.EmitBlock(RHSBlock); - - Visit(E->getRHS()); - Builder.CreateBr(ContBlock); - RHSBlock = Builder.GetInsertBlock(); - - CGF.EmitBlock(ContBlock); -} - -void AggExprEmitter::EmitNonConstInit(InitListExpr *E) { - - const llvm::PointerType *APType = - cast(DestPtr->getType()); - const llvm::Type *DestType = APType->getElementType(); - - if (const llvm::ArrayType *AType = dyn_cast(DestType)) { - unsigned NumInitElements = E->getNumInits(); - - llvm::Value *Idxs[] = { - llvm::Constant::getNullValue(llvm::Type::Int32Ty), - NULL - }; - llvm::Value *NextVal = NULL; - unsigned i; - for (i = 0; i != NumInitElements; ++i) { - Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2,".array"); - Expr *Init = E->getInit(i); - if (isa(Init)) - CGF.EmitAggExpr(Init, NextVal, VolatileDest); - else - Builder.CreateStore(CGF.EmitScalarExpr(Init), NextVal); - } - - // Emit remaining default initializers - unsigned NumArrayElements = AType->getNumElements(); - QualType QType = E->getInit(0)->getType(); - const llvm::Type *EType = AType->getElementType(); - for (/*Do not initialize i*/; i < NumArrayElements; ++i) { - Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2,".array"); - if (EType->isFirstClassType()) - Builder.CreateStore(llvm::Constant::getNullValue(EType), NextVal); - else - EmitAggregateClear(NextVal, QType); - } - } else - assert(false && "Invalid initializer"); -} - -void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { - - if (E->isConstantExpr(CGF.CGM.getContext(), NULL)) { - llvm::Constant *V = CGF.CGM.EmitConstantExpr(E); - // Create global value to hold this array. - V = new llvm::GlobalVariable(V->getType(), true, - llvm::GlobalValue::InternalLinkage, - V, ".array", - &CGF.CGM.getModule()); - - EmitAggregateCopy(DestPtr, V , E->getType()); - return; - } else { - if (!E->getType()->isArrayType()) { - CGF.WarnUnsupported(E, "aggregate init-list expression"); - return; - } - EmitNonConstInit(E); - } -} - -//===----------------------------------------------------------------------===// -// Entry Points into this File -//===----------------------------------------------------------------------===// - -/// EmitAggExpr - Emit the computation of the specified expression of -/// aggregate type. The result is computed into DestPtr. Note that if -/// DestPtr is null, the value of the aggregate expression is not needed. -void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, - bool VolatileDest) { - assert(E && hasAggregateLLVMType(E->getType()) && - "Invalid aggregate expression to emit"); - - AggExprEmitter(*this, DestPtr, VolatileDest).Visit(const_cast(E)); -} diff --git a/clang/CodeGen/CGExprComplex.cpp b/clang/CodeGen/CGExprComplex.cpp deleted file mode 100644 index b1de93570d9..00000000000 --- a/clang/CodeGen/CGExprComplex.cpp +++ /dev/null @@ -1,542 +0,0 @@ -//===--- CGExprComplex.cpp - Emit LLVM Code for Complex Exprs -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Expr nodes with complex types as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/AST.h" -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Compiler.h" -using namespace clang; -using namespace CodeGen; - -//===----------------------------------------------------------------------===// -// Complex Expression Emitter -//===----------------------------------------------------------------------===// - -typedef CodeGenFunction::ComplexPairTy ComplexPairTy; - -namespace { -class VISIBILITY_HIDDEN ComplexExprEmitter - : public StmtVisitor { - CodeGenFunction &CGF; - llvm::LLVMFoldingBuilder &Builder; -public: - ComplexExprEmitter(CodeGenFunction &cgf) : CGF(cgf), Builder(CGF.Builder) { - } - - - //===--------------------------------------------------------------------===// - // Utilities - //===--------------------------------------------------------------------===// - - /// EmitLoadOfLValue - Given an expression with complex type that represents a - /// value l-value, this method emits the address of the l-value, then loads - /// and returns the result. - ComplexPairTy EmitLoadOfLValue(const Expr *E) { - LValue LV = CGF.EmitLValue(E); - // FIXME: Volatile - return EmitLoadOfComplex(LV.getAddress(), false); - } - - /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load - /// the real and imaginary pieces. - ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile); - - /// EmitStoreOfComplex - Store the specified real/imag parts into the - /// specified value pointer. - void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol); - - /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. - ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType, - QualType DestType); - - //===--------------------------------------------------------------------===// - // Visitor Methods - //===--------------------------------------------------------------------===// - - ComplexPairTy VisitStmt(Stmt *S) { - S->dump(CGF.getContext().getSourceManager()); - assert(0 && "Stmt can't have complex result type!"); - return ComplexPairTy(); - } - ComplexPairTy VisitExpr(Expr *S); - ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());} - ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL); - - // l-values. - ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); } - - // FIXME: CompoundLiteralExpr - - ComplexPairTy EmitCast(Expr *Op, QualType DestTy); - ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) { - // Unlike for scalars, we don't have to worry about function->ptr demotion - // here. - return EmitCast(E->getSubExpr(), E->getType()); - } - ComplexPairTy VisitCastExpr(CastExpr *E) { - return EmitCast(E->getSubExpr(), E->getType()); - } - ComplexPairTy VisitCallExpr(const CallExpr *E); - ComplexPairTy VisitStmtExpr(const StmtExpr *E); - ComplexPairTy VisitOverloadExpr(const OverloadExpr *OE); - - // Operators. - ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E, - bool isInc, bool isPre); - ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) { - return VisitPrePostIncDec(E, false, false); - } - ComplexPairTy VisitUnaryPostInc(const UnaryOperator *E) { - return VisitPrePostIncDec(E, true, false); - } - ComplexPairTy VisitUnaryPreDec(const UnaryOperator *E) { - return VisitPrePostIncDec(E, false, true); - } - ComplexPairTy VisitUnaryPreInc(const UnaryOperator *E) { - return VisitPrePostIncDec(E, true, true); - } - ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); } - ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) { - return Visit(E->getSubExpr()); - } - ComplexPairTy VisitUnaryMinus (const UnaryOperator *E); - ComplexPairTy VisitUnaryNot (const UnaryOperator *E); - // LNot,SizeOf,AlignOf,Real,Imag never return complex. - ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) { - return Visit(E->getSubExpr()); - } - - struct BinOpInfo { - ComplexPairTy LHS; - ComplexPairTy RHS; - QualType Ty; // Computation Type. - }; - - BinOpInfo EmitBinOps(const BinaryOperator *E); - ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E, - ComplexPairTy (ComplexExprEmitter::*Func) - (const BinOpInfo &)); - - ComplexPairTy EmitBinAdd(const BinOpInfo &Op); - ComplexPairTy EmitBinSub(const BinOpInfo &Op); - ComplexPairTy EmitBinMul(const BinOpInfo &Op); - ComplexPairTy EmitBinDiv(const BinOpInfo &Op); - - ComplexPairTy VisitBinMul(const BinaryOperator *E) { - return EmitBinMul(EmitBinOps(E)); - } - ComplexPairTy VisitBinAdd(const BinaryOperator *E) { - return EmitBinAdd(EmitBinOps(E)); - } - ComplexPairTy VisitBinSub(const BinaryOperator *E) { - return EmitBinSub(EmitBinOps(E)); - } - ComplexPairTy VisitBinDiv(const BinaryOperator *E) { - return EmitBinDiv(EmitBinOps(E)); - } - - // Compound assignments. - ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) { - return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd); - } - ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) { - return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub); - } - ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) { - return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul); - } - ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) { - return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv); - } - - // GCC rejects rem/and/or/xor for integer complex. - // Logical and/or always return int, never complex. - - // No comparisons produce a complex result. - ComplexPairTy VisitBinAssign (const BinaryOperator *E); - ComplexPairTy VisitBinComma (const BinaryOperator *E); - - - ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO); - ComplexPairTy VisitChooseExpr(ChooseExpr *CE); -}; -} // end anonymous namespace. - -//===----------------------------------------------------------------------===// -// Utilities -//===----------------------------------------------------------------------===// - -/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to -/// load the real and imaginary pieces, returning them as Real/Imag. -ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr, - bool isVolatile) { - llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1); - - llvm::SmallString<64> Name(SrcPtr->getNameStart(), - SrcPtr->getNameStart()+SrcPtr->getNameLen()); - - Name += ".realp"; - llvm::Value *Ops[] = {Zero, Zero}; - llvm::Value *RealPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str()); - - Name.pop_back(); // .realp -> .real - llvm::Value *Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str()); - - Name.resize(Name.size()-4); // .real -> .imagp - Name += "imagp"; - - Ops[1] = One; // { Ops = { Zero, One } - llvm::Value *ImagPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str()); - - Name.pop_back(); // .imagp -> .imag - llvm::Value *Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str()); - return ComplexPairTy(Real, Imag); -} - -/// EmitStoreOfComplex - Store the specified real/imag parts into the -/// specified value pointer. -void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr, - bool isVolatile) { - llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1); - - llvm::Value *Ops[] = {Zero, Zero}; - llvm::Value *RealPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "real"); - - Ops[1] = One; // { Ops = { Zero, One } - llvm::Value *ImagPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "imag"); - - Builder.CreateStore(Val.first, RealPtr, isVolatile); - Builder.CreateStore(Val.second, ImagPtr, isVolatile); -} - - - -//===----------------------------------------------------------------------===// -// Visitor Methods -//===----------------------------------------------------------------------===// - -ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) { - CGF.WarnUnsupported(E, "complex expression"); - const llvm::Type *EltTy = - CGF.ConvertType(E->getType()->getAsComplexType()->getElementType()); - llvm::Value *U = llvm::UndefValue::get(EltTy); - return ComplexPairTy(U, U); -} - -ComplexPairTy ComplexExprEmitter:: -VisitImaginaryLiteral(const ImaginaryLiteral *IL) { - llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr()); - return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag); -} - - -ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) { - return CGF.EmitCallExpr(E).getComplexVal(); -} - -ComplexPairTy ComplexExprEmitter::VisitOverloadExpr(const OverloadExpr *E) { - return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), - E->getNumArgs(CGF.getContext())).getComplexVal(); -} - -ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) { - return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal(); -} - -/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. -ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val, - QualType SrcType, - QualType DestType) { - // Get the src/dest element type. - SrcType = cast(SrcType.getCanonicalType())->getElementType(); - DestType = cast(DestType.getCanonicalType())->getElementType(); - - // C99 6.3.1.6: When a value of complextype is converted to another - // complex type, both the real and imaginary parts followthe conversion - // rules for the corresponding real types. - Val.first = CGF.EmitScalarConversion(Val.first, SrcType, DestType); - Val.second = CGF.EmitScalarConversion(Val.second, SrcType, DestType); - return Val; -} - -ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) { - // Two cases here: cast from (complex to complex) and (scalar to complex). - if (Op->getType()->isComplexType()) - return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy); - - // C99 6.3.1.7: When a value of real type is converted to a complex type, the - // real part of the complex result value is determined by the rules of - // conversion to the corresponding real type and the imaginary part of the - // complex result value is a positive zero or an unsigned zero. - llvm::Value *Elt = CGF.EmitScalarExpr(Op); - - // Convert the input element to the element type of the complex. - DestTy = cast(DestTy.getCanonicalType())->getElementType(); - Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy); - - // Return (realval, 0). - return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType())); -} - -ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, - bool isInc, bool isPre) { - LValue LV = CGF.EmitLValue(E->getSubExpr()); - // FIXME: Handle volatile! - ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), false); - - uint64_t AmountVal = isInc ? 1 : -1; - - llvm::Value *NextVal; - if (isa(InVal.first->getType())) - NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal); - else if (InVal.first->getType() == llvm::Type::FloatTy) - // FIXME: Handle long double. - NextVal = - llvm::ConstantFP::get(InVal.first->getType(), - llvm::APFloat(static_cast(AmountVal))); - else { - // FIXME: Handle long double. - assert(InVal.first->getType() == llvm::Type::DoubleTy); - NextVal = - llvm::ConstantFP::get(InVal.first->getType(), - llvm::APFloat(static_cast(AmountVal))); - } - - // Add the inc/dec to the real part. - NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); - - ComplexPairTy IncVal(NextVal, InVal.second); - - // Store the updated result through the lvalue. - EmitStoreOfComplex(IncVal, LV.getAddress(), false); /* FIXME: Volatile */ - - // If this is a postinc, return the value read from memory, otherwise use the - // updated value. - return isPre ? IncVal : InVal; -} - -ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { - ComplexPairTy Op = Visit(E->getSubExpr()); - llvm::Value *ResR = Builder.CreateNeg(Op.first, "neg.r"); - llvm::Value *ResI = Builder.CreateNeg(Op.second, "neg.i"); - return ComplexPairTy(ResR, ResI); -} - -ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) { - // ~(a+ib) = a + i*-b - ComplexPairTy Op = Visit(E->getSubExpr()); - llvm::Value *ResI = Builder.CreateNeg(Op.second, "conj.i"); - return ComplexPairTy(Op.first, ResI); -} - -ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) { - llvm::Value *ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r"); - llvm::Value *ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i"); - return ComplexPairTy(ResR, ResI); -} - -ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) { - llvm::Value *ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r"); - llvm::Value *ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i"); - return ComplexPairTy(ResR, ResI); -} - - -ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { - llvm::Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl"); - llvm::Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr"); - llvm::Value *ResR = Builder.CreateSub(ResRl, ResRr, "mul.r"); - - llvm::Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il"); - llvm::Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir"); - llvm::Value *ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i"); - return ComplexPairTy(ResR, ResI); -} - -ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { - llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second; - llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second; - - // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) - llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c - llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d - llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd - - llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c - llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d - llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd - - llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c - llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d - llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad - - llvm::Value *DSTr, *DSTi; - if (Tmp3->getType()->isFloatingPoint()) { - DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp"); - DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp"); - } else { - if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) { - DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp"); - DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp"); - } else { - DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp"); - DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp"); - } - } - - return ComplexPairTy(DSTr, DSTi); -} - -ComplexExprEmitter::BinOpInfo -ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) { - BinOpInfo Ops; - Ops.LHS = Visit(E->getLHS()); - Ops.RHS = Visit(E->getRHS()); - Ops.Ty = E->getType(); - return Ops; -} - - -// Compound assignments. -ComplexPairTy ComplexExprEmitter:: -EmitCompoundAssign(const CompoundAssignOperator *E, - ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){ - QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType(); - - // Load the LHS and RHS operands. - LValue LHSLV = CGF.EmitLValue(E->getLHS()); - - BinOpInfo OpInfo; - OpInfo.Ty = E->getComputationType(); - - // We know the LHS is a complex lvalue. - OpInfo.LHS = EmitLoadOfComplex(LHSLV.getAddress(), false);// FIXME: Volatile. - OpInfo.LHS = EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty); - - // It is possible for the RHS to be complex or scalar. - OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty); - - // Expand the binary operator. - ComplexPairTy Result = (this->*Func)(OpInfo); - - // Truncate the result back to the LHS type. - Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); - - // Store the result value into the LHS lvalue. - EmitStoreOfComplex(Result, LHSLV.getAddress(), false); // FIXME: VOLATILE - return Result; -} - -ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { - assert(E->getLHS()->getType().getCanonicalType() == - E->getRHS()->getType().getCanonicalType() && "Invalid assignment"); - // Emit the RHS. - ComplexPairTy Val = Visit(E->getRHS()); - - // Compute the address to store into. - LValue LHS = CGF.EmitLValue(E->getLHS()); - - // Store into it. - // FIXME: Volatility! - EmitStoreOfComplex(Val, LHS.getAddress(), false); - return Val; -} - -ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) { - CGF.EmitStmt(E->getLHS()); - return Visit(E->getRHS()); -} - -ComplexPairTy ComplexExprEmitter:: -VisitConditionalOperator(const ConditionalOperator *E) { - llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?"); - llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:"); - llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont"); - - llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); - Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); - - CGF.EmitBlock(LHSBlock); - - // Handle the GNU extension for missing LHS. - assert(E->getLHS() && "Must have LHS for complex value"); - - ComplexPairTy LHS = Visit(E->getLHS()); - Builder.CreateBr(ContBlock); - LHSBlock = Builder.GetInsertBlock(); - - CGF.EmitBlock(RHSBlock); - - ComplexPairTy RHS = Visit(E->getRHS()); - Builder.CreateBr(ContBlock); - RHSBlock = Builder.GetInsertBlock(); - - CGF.EmitBlock(ContBlock); - - // Create a PHI node for the real part. - llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r"); - RealPN->reserveOperandSpace(2); - RealPN->addIncoming(LHS.first, LHSBlock); - RealPN->addIncoming(RHS.first, RHSBlock); - - // Create a PHI node for the imaginary part. - llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i"); - ImagPN->reserveOperandSpace(2); - ImagPN->addIncoming(LHS.second, LHSBlock); - ImagPN->addIncoming(RHS.second, RHSBlock); - - return ComplexPairTy(RealPN, ImagPN); -} - -ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) { - // Emit the LHS or RHS as appropriate. - return Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() :E->getRHS()); -} - -//===----------------------------------------------------------------------===// -// Entry Point into this File -//===----------------------------------------------------------------------===// - -/// EmitComplexExpr - Emit the computation of the specified expression of -/// complex type, ignoring the result. -ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E) { - assert(E && E->getType()->isComplexType() && - "Invalid complex expression to emit"); - - return ComplexExprEmitter(*this).Visit(const_cast(E)); -} - -/// EmitComplexExprIntoAddr - Emit the computation of the specified expression -/// of complex type, storing into the specified Value*. -void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E, - llvm::Value *DestAddr, - bool DestIsVolatile) { - assert(E && E->getType()->isComplexType() && - "Invalid complex expression to emit"); - ComplexExprEmitter Emitter(*this); - ComplexPairTy Val = Emitter.Visit(const_cast(E)); - Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile); -} - -/// LoadComplexFromAddr - Load a complex number from the specified address. -ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr, - bool SrcIsVolatile) { - return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile); -} diff --git a/clang/CodeGen/CGExprConstant.cpp b/clang/CodeGen/CGExprConstant.cpp deleted file mode 100644 index e2405b88f37..00000000000 --- a/clang/CodeGen/CGExprConstant.cpp +++ /dev/null @@ -1,627 +0,0 @@ -//===--- CGExprConstant.cpp - Emit LLVM Code from Constant Expressions ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Constant Expr nodes as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/AST.h" -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Support/Compiler.h" -using namespace clang; -using namespace CodeGen; - -namespace { -class VISIBILITY_HIDDEN ConstExprEmitter : - public StmtVisitor { - CodeGenModule &CGM; - CodeGenFunction *CGF; -public: - ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf) - : CGM(cgm), CGF(cgf) { - } - - //===--------------------------------------------------------------------===// - // Visitor Methods - //===--------------------------------------------------------------------===// - - llvm::Constant *VisitStmt(Stmt *S) { - CGM.WarnUnsupported(S, "constant expression"); - QualType T = cast(S)->getType(); - return llvm::UndefValue::get(CGM.getTypes().ConvertType(T)); - } - - llvm::Constant *VisitParenExpr(ParenExpr *PE) { - return Visit(PE->getSubExpr()); - } - - // Leaves - llvm::Constant *VisitIntegerLiteral(const IntegerLiteral *E) { - return llvm::ConstantInt::get(E->getValue()); - } - llvm::Constant *VisitFloatingLiteral(const FloatingLiteral *E) { - return llvm::ConstantFP::get(ConvertType(E->getType()), E->getValue()); - } - llvm::Constant *VisitCharacterLiteral(const CharacterLiteral *E) { - return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); - } - llvm::Constant *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { - return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); - } - - llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - return Visit(E->getInitializer()); - } - - llvm::Constant *VisitCastExpr(const CastExpr* E) { - llvm::Constant *C = Visit(E->getSubExpr()); - - return EmitConversion(C, E->getSubExpr()->getType(), E->getType()); - } - - llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, - const llvm::ArrayType *AType) { - std::vector Elts; - unsigned NumInitElements = ILE->getNumInits(); - // FIXME: Check for wide strings - if (NumInitElements > 0 && isa(ILE->getInit(0)) && - ILE->getType()->getAsArrayType()->getElementType()->isCharType()) - return Visit(ILE->getInit(0)); - const llvm::Type *ElemTy = AType->getElementType(); - unsigned NumElements = AType->getNumElements(); - - // Initialising an array requires us to automatically - // initialise any elements that have not been initialised explicitly - unsigned NumInitableElts = std::min(NumInitElements, NumElements); - - // Copy initializer elements. - unsigned i = 0; - for (; i < NumInitableElts; ++i) { - - llvm::Constant *C = Visit(ILE->getInit(i)); - // FIXME: Remove this when sema of initializers is finished (and the code - // above). - if (C == 0 && ILE->getInit(i)->getType()->isVoidType()) { - if (ILE->getType()->isVoidType()) return 0; - return llvm::UndefValue::get(AType); - } - assert (C && "Failed to create initializer expression"); - Elts.push_back(C); - } - - // Initialize remaining array elements. - for (; i < NumElements; ++i) - Elts.push_back(llvm::Constant::getNullValue(ElemTy)); - - return llvm::ConstantArray::get(AType, Elts); - } - - llvm::Constant *EmitStructInitialization(InitListExpr *ILE, - const llvm::StructType *SType) { - - TagDecl *TD = ILE->getType()->getAsRecordType()->getDecl(); - std::vector Elts; - const CGRecordLayout *CGR = CGM.getTypes().getCGRecordLayout(TD); - unsigned NumInitElements = ILE->getNumInits(); - unsigned NumElements = SType->getNumElements(); - - // Initialising an structure requires us to automatically - // initialise any elements that have not been initialised explicitly - unsigned NumInitableElts = std::min(NumInitElements, NumElements); - - // Copy initializer elements. Skip padding fields. - unsigned EltNo = 0; // Element no in ILE - unsigned FieldNo = 0; // Field no in SType - while (EltNo < NumInitableElts) { - - // Zero initialize padding field. - if (CGR->isPaddingField(FieldNo)) { - const llvm::Type *FieldTy = SType->getElementType(FieldNo); - Elts.push_back(llvm::Constant::getNullValue(FieldTy)); - FieldNo++; - continue; - } - - llvm::Constant *C = Visit(ILE->getInit(EltNo)); - // FIXME: Remove this when sema of initializers is finished (and the code - // above). - if (C == 0 && ILE->getInit(EltNo)->getType()->isVoidType()) { - if (ILE->getType()->isVoidType()) return 0; - return llvm::UndefValue::get(SType); - } - assert (C && "Failed to create initializer expression"); - Elts.push_back(C); - EltNo++; - FieldNo++; - } - - // Initialize remaining structure elements. - for (unsigned i = Elts.size(); i < NumElements; ++i) { - const llvm::Type *FieldTy = SType->getElementType(i); - Elts.push_back(llvm::Constant::getNullValue(FieldTy)); - } - - return llvm::ConstantStruct::get(SType, Elts); - } - - llvm::Constant *EmitVectorInitialization(InitListExpr *ILE, - const llvm::VectorType *VType) { - - std::vector Elts; - unsigned NumInitElements = ILE->getNumInits(); - unsigned NumElements = VType->getNumElements(); - - assert (NumInitElements == NumElements - && "Unsufficient vector init elelments"); - // Copy initializer elements. - unsigned i = 0; - for (; i < NumElements; ++i) { - - llvm::Constant *C = Visit(ILE->getInit(i)); - // FIXME: Remove this when sema of initializers is finished (and the code - // above). - if (C == 0 && ILE->getInit(i)->getType()->isVoidType()) { - if (ILE->getType()->isVoidType()) return 0; - return llvm::UndefValue::get(VType); - } - assert (C && "Failed to create initializer expression"); - Elts.push_back(C); - } - - return llvm::ConstantVector::get(VType, Elts); - } - - llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { - const llvm::CompositeType *CType = - dyn_cast(ConvertType(ILE->getType())); - - if (!CType) { - // We have a scalar in braces. Just use the first element. - return Visit(ILE->getInit(0)); - } - - if (const llvm::ArrayType *AType = dyn_cast(CType)) - return EmitArrayInitialization(ILE, AType); - - if (const llvm::StructType *SType = dyn_cast(CType)) - return EmitStructInitialization(ILE, SType); - - if (const llvm::VectorType *VType = dyn_cast(CType)) - return EmitVectorInitialization(ILE, VType); - - // Make sure we have an array at this point - assert(0 && "Unable to handle InitListExpr"); - // Get rid of control reaches end of void function warning. - // Not reached. - return 0; - } - - llvm::Constant *VisitImplicitCastExpr(ImplicitCastExpr *ICExpr) { - Expr* SExpr = ICExpr->getSubExpr(); - QualType SType = SExpr->getType(); - llvm::Constant *C; // the intermediate expression - QualType T; // the type of the intermediate expression - if (SType->isArrayType()) { - // Arrays decay to a pointer to the first element - // VLAs would require special handling, but they can't occur here - C = EmitLValue(SExpr); - llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *Ops[] = {Idx0, Idx0}; - C = llvm::ConstantExpr::getGetElementPtr(C, Ops, 2); - - QualType ElemType = SType->getAsArrayType()->getElementType(); - T = CGM.getContext().getPointerType(ElemType); - } else if (SType->isFunctionType()) { - // Function types decay to a pointer to the function - C = EmitLValue(SExpr); - T = CGM.getContext().getPointerType(SType); - } else { - C = Visit(SExpr); - T = SType; - } - - // Perform the conversion; note that an implicit cast can both promote - // and convert an array/function - return EmitConversion(C, T, ICExpr->getType()); - } - - llvm::Constant *VisitStringLiteral(StringLiteral *E) { - const char *StrData = E->getStrData(); - unsigned Len = E->getByteLength(); - assert(!E->getType()->isPointerType() && "Strings are always arrays"); - - // Otherwise this must be a string initializing an array in a static - // initializer. Don't emit it as the address of the string, emit the string - // data itself as an inline array. - const ConstantArrayType *CAT = E->getType()->getAsConstantArrayType(); - assert(CAT && "String isn't pointer or array!"); - - std::string Str(StrData, StrData + Len); - // Null terminate the string before potentially truncating it. - // FIXME: What about wchar_t strings? - Str.push_back(0); - - uint64_t RealLen = CAT->getSize().getZExtValue(); - // String or grow the initializer to the required size. - if (RealLen != Str.size()) - Str.resize(RealLen); - - return llvm::ConstantArray::get(Str, false); - } - - llvm::Constant *VisitDeclRefExpr(DeclRefExpr *E) { - const ValueDecl *Decl = E->getDecl(); - if (const EnumConstantDecl *EC = dyn_cast(Decl)) - return llvm::ConstantInt::get(EC->getInitVal()); - assert(0 && "Unsupported decl ref type!"); - return 0; - } - - llvm::Constant *VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) { - return EmitSizeAlignOf(E->getArgumentType(), E->getType(), E->isSizeOf()); - } - - // Unary operators - llvm::Constant *VisitUnaryPlus(const UnaryOperator *E) { - return Visit(E->getSubExpr()); - } - llvm::Constant *VisitUnaryMinus(const UnaryOperator *E) { - return llvm::ConstantExpr::getNeg(Visit(E->getSubExpr())); - } - llvm::Constant *VisitUnaryNot(const UnaryOperator *E) { - return llvm::ConstantExpr::getNot(Visit(E->getSubExpr())); - } - llvm::Constant *VisitUnaryLNot(const UnaryOperator *E) { - llvm::Constant *SubExpr = Visit(E->getSubExpr()); - - if (E->getSubExpr()->getType()->isRealFloatingType()) { - // Compare against 0.0 for fp scalars. - llvm::Constant *Zero = llvm::Constant::getNullValue(SubExpr->getType()); - SubExpr = llvm::ConstantExpr::getFCmp(llvm::FCmpInst::FCMP_UEQ, SubExpr, - Zero); - } else { - assert((E->getSubExpr()->getType()->isIntegerType() || - E->getSubExpr()->getType()->isPointerType()) && - "Unknown scalar type to convert"); - // Compare against an integer or pointer null. - llvm::Constant *Zero = llvm::Constant::getNullValue(SubExpr->getType()); - SubExpr = llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_EQ, SubExpr, - Zero); - } - - return llvm::ConstantExpr::getZExt(SubExpr, ConvertType(E->getType())); - } - llvm::Constant *VisitUnarySizeOf(const UnaryOperator *E) { - return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), true); - } - llvm::Constant *VisitUnaryAlignOf(const UnaryOperator *E) { - return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), false); - } - llvm::Constant *VisitUnaryAddrOf(const UnaryOperator *E) { - return EmitLValue(E->getSubExpr()); - } - llvm::Constant *VisitUnaryOffsetOf(const UnaryOperator *E) { - int64_t Val = E->evaluateOffsetOf(CGM.getContext()); - - assert(E->getType()->isIntegerType() && "Result type must be an integer!"); - - uint32_t ResultWidth = - static_cast(CGM.getContext().getTypeSize(E->getType())); - return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); - } - - // Binary operators - llvm::Constant *VisitBinOr(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - return llvm::ConstantExpr::getOr(LHS, RHS); - } - llvm::Constant *VisitBinSub(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - if (!isa(RHS->getType())) { - // pointer - int - if (isa(LHS->getType())) { - llvm::Constant *Idx = llvm::ConstantExpr::getNeg(RHS); - - return llvm::ConstantExpr::getGetElementPtr(LHS, &Idx, 1); - } - - // int - int - return llvm::ConstantExpr::getSub(LHS, RHS); - } - - assert(0 && "Unhandled bin sub case!"); - return 0; - } - - llvm::Constant *VisitBinShl(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - // LLVM requires the LHS and RHS to be the same type: promote or truncate the - // RHS to the same size as the LHS. - if (LHS->getType() != RHS->getType()) - RHS = llvm::ConstantExpr::getIntegerCast(RHS, LHS->getType(), false); - - return llvm::ConstantExpr::getShl(LHS, RHS); - } - - llvm::Constant *VisitBinMul(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - return llvm::ConstantExpr::getMul(LHS, RHS); - } - - llvm::Constant *VisitBinDiv(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - if (LHS->getType()->isFPOrFPVector()) - return llvm::ConstantExpr::getFDiv(LHS, RHS); - else if (E->getType()->isUnsignedIntegerType()) - return llvm::ConstantExpr::getUDiv(LHS, RHS); - else - return llvm::ConstantExpr::getSDiv(LHS, RHS); - } - - llvm::Constant *VisitBinAdd(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - if (!E->getType()->isPointerType()) - return llvm::ConstantExpr::getAdd(LHS, RHS); - - llvm::Constant *Ptr, *Idx; - if (isa(LHS->getType())) { // pointer + int - Ptr = LHS; - Idx = RHS; - } else { // int + pointer - Ptr = RHS; - Idx = LHS; - } - - return llvm::ConstantExpr::getGetElementPtr(Ptr, &Idx, 1); - } - - llvm::Constant *VisitBinAnd(const BinaryOperator *E) { - llvm::Constant *LHS = Visit(E->getLHS()); - llvm::Constant *RHS = Visit(E->getRHS()); - - return llvm::ConstantExpr::getAnd(LHS, RHS); - } - - // Utility methods - const llvm::Type *ConvertType(QualType T) { - return CGM.getTypes().ConvertType(T); - } - - llvm::Constant *EmitConversionToBool(llvm::Constant *Src, QualType SrcType) { - assert(SrcType->isCanonical() && "EmitConversion strips typedefs"); - - if (SrcType->isRealFloatingType()) { - // Compare against 0.0 for fp scalars. - llvm::Constant *Zero = llvm::Constant::getNullValue(Src->getType()); - return llvm::ConstantExpr::getFCmp(llvm::FCmpInst::FCMP_UNE, Src, Zero); - } - - assert((SrcType->isIntegerType() || SrcType->isPointerType()) && - "Unknown scalar type to convert"); - - // Compare against an integer or pointer null. - llvm::Constant *Zero = llvm::Constant::getNullValue(Src->getType()); - return llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_NE, Src, Zero); - } - - llvm::Constant *EmitConversion(llvm::Constant *Src, QualType SrcType, - QualType DstType) { - SrcType = SrcType.getCanonicalType(); - DstType = DstType.getCanonicalType(); - if (SrcType == DstType) return Src; - - // Handle conversions to bool first, they are special: comparisons against 0. - if (DstType->isBooleanType()) - return EmitConversionToBool(Src, SrcType); - - const llvm::Type *DstTy = ConvertType(DstType); - - // Ignore conversions like int -> uint. - if (Src->getType() == DstTy) - return Src; - - // Handle pointer conversions next: pointers can only be converted to/from - // other pointers and integers. - if (isa(DstType)) { - // The source value may be an integer, or a pointer. - if (isa(Src->getType())) - return llvm::ConstantExpr::getBitCast(Src, DstTy); - assert(SrcType->isIntegerType() &&"Not ptr->ptr or int->ptr conversion?"); - return llvm::ConstantExpr::getIntToPtr(Src, DstTy); - } - - if (isa(SrcType)) { - // Must be an ptr to int cast. - assert(isa(DstTy) && "not ptr->int?"); - return llvm::ConstantExpr::getPtrToInt(Src, DstTy); - } - - // A scalar source can be splatted to a vector of the same element type - if (isa(DstTy) && !isa(SrcType)) { - const llvm::VectorType *VT = cast(DstTy); - assert((VT->getElementType() == Src->getType()) && - "Vector element type must match scalar type to splat."); - unsigned NumElements = DstType->getAsVectorType()->getNumElements(); - llvm::SmallVector Elements; - for (unsigned i = 0; i < NumElements; i++) - Elements.push_back(Src); - - return llvm::ConstantVector::get(&Elements[0], NumElements); - } - - if (isa(Src->getType()) || - isa(DstTy)) { - return llvm::ConstantExpr::getBitCast(Src, DstTy); - } - - // Finally, we have the arithmetic types: real int/float. - if (isa(Src->getType())) { - bool InputSigned = SrcType->isSignedIntegerType(); - if (isa(DstTy)) - return llvm::ConstantExpr::getIntegerCast(Src, DstTy, InputSigned); - else if (InputSigned) - return llvm::ConstantExpr::getSIToFP(Src, DstTy); - else - return llvm::ConstantExpr::getUIToFP(Src, DstTy); - } - - assert(Src->getType()->isFloatingPoint() && "Unknown real conversion"); - if (isa(DstTy)) { - if (DstType->isSignedIntegerType()) - return llvm::ConstantExpr::getFPToSI(Src, DstTy); - else - return llvm::ConstantExpr::getFPToUI(Src, DstTy); - } - - assert(DstTy->isFloatingPoint() && "Unknown real conversion"); - if (DstTy->getTypeID() < Src->getType()->getTypeID()) - return llvm::ConstantExpr::getFPTrunc(Src, DstTy); - else - return llvm::ConstantExpr::getFPExtend(Src, DstTy); - } - - llvm::Constant *EmitSizeAlignOf(QualType TypeToSize, - QualType RetType, bool isSizeOf) { - std::pair Info = - CGM.getContext().getTypeInfo(TypeToSize); - - uint64_t Val = isSizeOf ? Info.first : Info.second; - Val /= 8; // Return size in bytes, not bits. - - assert(RetType->isIntegerType() && "Result type must be an integer!"); - - uint32_t ResultWidth = - static_cast(CGM.getContext().getTypeSize(RetType)); - return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); - } - - llvm::Constant *EmitLValue(Expr *E) { - switch (E->getStmtClass()) { - default: break; - case Expr::ParenExprClass: - // Elide parenthesis - return EmitLValue(cast(E)->getSubExpr()); - case Expr::CompoundLiteralExprClass: { - // Note that due to the nature of compound literals, this is guaranteed - // to be the only use of the variable, so we just generate it here. - CompoundLiteralExpr *CLE = cast(E); - llvm::Constant* C = Visit(CLE->getInitializer()); - C = new llvm::GlobalVariable(C->getType(),E->getType().isConstQualified(), - llvm::GlobalValue::InternalLinkage, - C, ".compoundliteral", &CGM.getModule()); - return C; - } - case Expr::DeclRefExprClass: { - ValueDecl *Decl = cast(E)->getDecl(); - if (const FunctionDecl *FD = dyn_cast(Decl)) - return CGM.GetAddrOfFunctionDecl(FD, false); - if (const FileVarDecl* VD = dyn_cast(Decl)) - return CGM.GetAddrOfGlobalVar(VD, false); - if (const BlockVarDecl* BVD = dyn_cast(Decl)) { - assert(CGF && "Can't access static local vars without CGF"); - return CGF->GetAddrOfStaticLocalVar(BVD); - } - break; - } - case Expr::MemberExprClass: { - MemberExpr* ME = cast(E); - llvm::Constant *Base; - if (ME->isArrow()) - Base = Visit(ME->getBase()); - else - Base = EmitLValue(ME->getBase()); - - unsigned FieldNumber = CGM.getTypes().getLLVMFieldNo(ME->getMemberDecl()); - llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, - FieldNumber); - llvm::Value *Ops[] = {Zero, Idx}; - return llvm::ConstantExpr::getGetElementPtr(Base, Ops, 2); - } - case Expr::ArraySubscriptExprClass: { - ArraySubscriptExpr* ASExpr = cast(E); - llvm::Constant *Base = Visit(ASExpr->getBase()); - llvm::Constant *Index = Visit(ASExpr->getIdx()); - assert(!ASExpr->getBase()->getType()->isVectorType() && - "Taking the address of a vector component is illegal!"); - return llvm::ConstantExpr::getGetElementPtr(Base, &Index, 1); - } - case Expr::StringLiteralClass: { - StringLiteral *String = cast(E); - assert(!String->isWide() && "Cannot codegen wide strings yet"); - const char *StrData = String->getStrData(); - unsigned Len = String->getByteLength(); - - return CGM.GetAddrOfConstantString(std::string(StrData, StrData + Len)); - } - case Expr::UnaryOperatorClass: { - UnaryOperator *Exp = cast(E); - switch (Exp->getOpcode()) { - default: break; - case UnaryOperator::Extension: - // Extension is just a wrapper for expressions - return EmitLValue(Exp->getSubExpr()); - case UnaryOperator::Real: - case UnaryOperator::Imag: { - // The address of __real or __imag is just a GEP off the address - // of the internal expression - llvm::Constant* C = EmitLValue(Exp->getSubExpr()); - llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, - Exp->getOpcode() == UnaryOperator::Imag); - llvm::Value *Ops[] = {Zero, Idx}; - return llvm::ConstantExpr::getGetElementPtr(C, Ops, 2); - } - case UnaryOperator::Deref: - // The address of a deref is just the value of the expression - return Visit(Exp->getSubExpr()); - } - break; - } - } - CGM.WarnUnsupported(E, "constant l-value expression"); - llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); - return llvm::UndefValue::get(Ty); - } - -}; - -} // end anonymous namespace. - - -llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, - CodeGenFunction *CGF) -{ - QualType type = E->getType().getCanonicalType(); - - if (type->isIntegerType()) { - llvm::APSInt Value(static_cast(Context.getTypeSize(type))); - if (E->isIntegerConstantExpr(Value, Context)) { - return llvm::ConstantInt::get(Value); - } - } - - return ConstExprEmitter(*this, CGF).Visit(const_cast(E)); -} diff --git a/clang/CodeGen/CGExprScalar.cpp b/clang/CodeGen/CGExprScalar.cpp deleted file mode 100644 index 892712a0d4c..00000000000 --- a/clang/CodeGen/CGExprScalar.cpp +++ /dev/null @@ -1,1185 +0,0 @@ -//===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Expr nodes with scalar LLVM types as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/AST.h" -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Intrinsics.h" -#include "llvm/Support/Compiler.h" -#include - -using namespace clang; -using namespace CodeGen; -using llvm::Value; - -//===----------------------------------------------------------------------===// -// Scalar Expression Emitter -//===----------------------------------------------------------------------===// - -struct BinOpInfo { - Value *LHS; - Value *RHS; - QualType Ty; // Computation Type. - const BinaryOperator *E; -}; - -namespace { -class VISIBILITY_HIDDEN ScalarExprEmitter - : public StmtVisitor { - CodeGenFunction &CGF; - llvm::LLVMFoldingBuilder &Builder; - CGObjCRuntime *Runtime; - - -public: - - ScalarExprEmitter(CodeGenFunction &cgf) : CGF(cgf), - Builder(CGF.Builder), - Runtime(CGF.CGM.getObjCRuntime()) { - } - - - //===--------------------------------------------------------------------===// - // Utilities - //===--------------------------------------------------------------------===// - - const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } - LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } - - Value *EmitLoadOfLValue(LValue LV, QualType T) { - return CGF.EmitLoadOfLValue(LV, T).getScalarVal(); - } - - /// EmitLoadOfLValue - Given an expression with complex type that represents a - /// value l-value, this method emits the address of the l-value, then loads - /// and returns the result. - Value *EmitLoadOfLValue(const Expr *E) { - // FIXME: Volatile - return EmitLoadOfLValue(EmitLValue(E), E->getType()); - } - - /// EmitConversionToBool - Convert the specified expression value to a - /// boolean (i1) truth value. This is equivalent to "Val != 0". - Value *EmitConversionToBool(Value *Src, QualType DstTy); - - /// EmitScalarConversion - Emit a conversion from the specified type to the - /// specified destination type, both of which are LLVM scalar types. - Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy); - - /// EmitComplexToScalarConversion - Emit a conversion from the specified - /// complex type to the specified destination type, where the destination - /// type is an LLVM scalar type. - Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, - QualType SrcTy, QualType DstTy); - - //===--------------------------------------------------------------------===// - // Visitor Methods - //===--------------------------------------------------------------------===// - - Value *VisitStmt(Stmt *S) { - S->dump(CGF.getContext().getSourceManager()); - assert(0 && "Stmt can't have complex result type!"); - return 0; - } - Value *VisitExpr(Expr *S); - Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); } - - // Leaves. - Value *VisitIntegerLiteral(const IntegerLiteral *E) { - return llvm::ConstantInt::get(E->getValue()); - } - Value *VisitFloatingLiteral(const FloatingLiteral *E) { - return llvm::ConstantFP::get(ConvertType(E->getType()), E->getValue()); - } - Value *VisitCharacterLiteral(const CharacterLiteral *E) { - return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); - } - Value *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { - return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); - } - Value *VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) { - return llvm::ConstantInt::get(ConvertType(E->getType()), - CGF.getContext().typesAreCompatible( - E->getArgType1(), E->getArgType2())); - } - Value *VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) { - return EmitSizeAlignOf(E->getArgumentType(), E->getType(), E->isSizeOf()); - } - - // l-values. - Value *VisitDeclRefExpr(DeclRefExpr *E) { - if (const EnumConstantDecl *EC = dyn_cast(E->getDecl())) - return llvm::ConstantInt::get(EC->getInitVal()); - return EmitLoadOfLValue(E); - } - Value *VisitObjCMessageExpr(ObjCMessageExpr *E); - Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); - Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); } - Value *VisitOCUVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } - Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); } - Value *VisitPreDefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } - - Value *VisitInitListExpr(InitListExpr *E) { - unsigned NumInitElements = E->getNumInits(); - - const llvm::VectorType *VType = - dyn_cast(ConvertType(E->getType())); - - // We have a scalar in braces. Just use the first element. - if (!VType) - return Visit(E->getInit(0)); - - unsigned NumVectorElements = VType->getNumElements(); - const llvm::Type *ElementType = VType->getElementType(); - - // Emit individual vector element stores. - llvm::Value *V = llvm::UndefValue::get(VType); - - // Emit initializers - unsigned i; - for (i = 0; i < NumInitElements; ++i) { - Value *NewV = Visit(E->getInit(i)); - Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - V = Builder.CreateInsertElement(V, NewV, Idx); - } - - // Emit remaining default initializers - for (/* Do not initialize i*/; i < NumVectorElements; ++i) { - Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - llvm::Value *NewV = llvm::Constant::getNullValue(ElementType); - V = Builder.CreateInsertElement(V, NewV, Idx); - } - - return V; - } - - Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - return Visit(E->getInitializer()); - } - - Value *VisitImplicitCastExpr(const ImplicitCastExpr *E); - Value *VisitCastExpr(const CastExpr *E) { - return EmitCastExpr(E->getSubExpr(), E->getType()); - } - Value *EmitCastExpr(const Expr *E, QualType T); - - Value *VisitCallExpr(const CallExpr *E) { - return CGF.EmitCallExpr(E).getScalarVal(); - } - - Value *VisitStmtExpr(const StmtExpr *E); - - // Unary Operators. - Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre); - Value *VisitUnaryPostDec(const UnaryOperator *E) { - return VisitPrePostIncDec(E, false, false); - } - Value *VisitUnaryPostInc(const UnaryOperator *E) { - return VisitPrePostIncDec(E, true, false); - } - Value *VisitUnaryPreDec(const UnaryOperator *E) { - return VisitPrePostIncDec(E, false, true); - } - Value *VisitUnaryPreInc(const UnaryOperator *E) { - return VisitPrePostIncDec(E, true, true); - } - Value *VisitUnaryAddrOf(const UnaryOperator *E) { - return EmitLValue(E->getSubExpr()).getAddress(); - } - Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); } - Value *VisitUnaryPlus(const UnaryOperator *E) { - return Visit(E->getSubExpr()); - } - Value *VisitUnaryMinus (const UnaryOperator *E); - Value *VisitUnaryNot (const UnaryOperator *E); - Value *VisitUnaryLNot (const UnaryOperator *E); - Value *VisitUnarySizeOf (const UnaryOperator *E) { - return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), true); - } - Value *VisitUnaryAlignOf (const UnaryOperator *E) { - return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), false); - } - Value *EmitSizeAlignOf(QualType TypeToSize, QualType RetType, - bool isSizeOf); - Value *VisitUnaryReal (const UnaryOperator *E); - Value *VisitUnaryImag (const UnaryOperator *E); - Value *VisitUnaryExtension(const UnaryOperator *E) { - return Visit(E->getSubExpr()); - } - Value *VisitUnaryOffsetOf(const UnaryOperator *E); - - // Binary Operators. - Value *EmitMul(const BinOpInfo &Ops) { - return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); - } - Value *EmitDiv(const BinOpInfo &Ops); - Value *EmitRem(const BinOpInfo &Ops); - Value *EmitAdd(const BinOpInfo &Ops); - Value *EmitSub(const BinOpInfo &Ops); - Value *EmitShl(const BinOpInfo &Ops); - Value *EmitShr(const BinOpInfo &Ops); - Value *EmitAnd(const BinOpInfo &Ops) { - return Builder.CreateAnd(Ops.LHS, Ops.RHS, "and"); - } - Value *EmitXor(const BinOpInfo &Ops) { - return Builder.CreateXor(Ops.LHS, Ops.RHS, "xor"); - } - Value *EmitOr (const BinOpInfo &Ops) { - return Builder.CreateOr(Ops.LHS, Ops.RHS, "or"); - } - - BinOpInfo EmitBinOps(const BinaryOperator *E); - Value *EmitCompoundAssign(const CompoundAssignOperator *E, - Value *(ScalarExprEmitter::*F)(const BinOpInfo &)); - - // Binary operators and binary compound assignment operators. -#define HANDLEBINOP(OP) \ - Value *VisitBin ## OP(const BinaryOperator *E) { \ - return Emit ## OP(EmitBinOps(E)); \ - } \ - Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \ - return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \ - } - HANDLEBINOP(Mul); - HANDLEBINOP(Div); - HANDLEBINOP(Rem); - HANDLEBINOP(Add); - // (Sub) - Sub is handled specially below for ptr-ptr subtract. - HANDLEBINOP(Shl); - HANDLEBINOP(Shr); - HANDLEBINOP(And); - HANDLEBINOP(Xor); - HANDLEBINOP(Or); -#undef HANDLEBINOP - Value *VisitBinSub(const BinaryOperator *E); - Value *VisitBinSubAssign(const CompoundAssignOperator *E) { - return EmitCompoundAssign(E, &ScalarExprEmitter::EmitSub); - } - - // Comparisons. - Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc, - unsigned SICmpOpc, unsigned FCmpOpc); -#define VISITCOMP(CODE, UI, SI, FP) \ - Value *VisitBin##CODE(const BinaryOperator *E) { \ - return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \ - llvm::FCmpInst::FP); } - VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT); - VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT); - VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE); - VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE); - VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ); - VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE); -#undef VISITCOMP - - Value *VisitBinAssign (const BinaryOperator *E); - - Value *VisitBinLAnd (const BinaryOperator *E); - Value *VisitBinLOr (const BinaryOperator *E); - Value *VisitBinComma (const BinaryOperator *E); - - // Other Operators. - Value *VisitConditionalOperator(const ConditionalOperator *CO); - Value *VisitChooseExpr(ChooseExpr *CE); - Value *VisitOverloadExpr(OverloadExpr *OE); - Value *VisitVAArgExpr(VAArgExpr *VE); - Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { - return CGF.EmitObjCStringLiteral(E); - } - Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E); -}; -} // end anonymous namespace. - -//===----------------------------------------------------------------------===// -// Utilities -//===----------------------------------------------------------------------===// - -/// EmitConversionToBool - Convert the specified expression value to a -/// boolean (i1) truth value. This is equivalent to "Val != 0". -Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { - assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs"); - - if (SrcType->isRealFloatingType()) { - // Compare against 0.0 for fp scalars. - llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType()); - return Builder.CreateFCmpUNE(Src, Zero, "tobool"); - } - - assert((SrcType->isIntegerType() || SrcType->isPointerType()) && - "Unknown scalar type to convert"); - - // Because of the type rules of C, we often end up computing a logical value, - // then zero extending it to int, then wanting it as a logical value again. - // Optimize this common case. - if (llvm::ZExtInst *ZI = dyn_cast(Src)) { - if (ZI->getOperand(0)->getType() == llvm::Type::Int1Ty) { - Value *Result = ZI->getOperand(0); - // If there aren't any more uses, zap the instruction to save space. - // Note that there can be more uses, for example if this - // is the result of an assignment. - if (ZI->use_empty()) - ZI->eraseFromParent(); - return Result; - } - } - - // Compare against an integer or pointer null. - llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType()); - return Builder.CreateICmpNE(Src, Zero, "tobool"); -} - -/// EmitScalarConversion - Emit a conversion from the specified type to the -/// specified destination type, both of which are LLVM scalar types. -Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, - QualType DstType) { - SrcType = SrcType.getCanonicalType(); - DstType = DstType.getCanonicalType(); - if (SrcType == DstType) return Src; - - if (DstType->isVoidType()) return 0; - - // Handle conversions to bool first, they are special: comparisons against 0. - if (DstType->isBooleanType()) - return EmitConversionToBool(Src, SrcType); - - const llvm::Type *DstTy = ConvertType(DstType); - - // Ignore conversions like int -> uint. - if (Src->getType() == DstTy) - return Src; - - // Handle pointer conversions next: pointers can only be converted to/from - // other pointers and integers. - if (isa(DstType)) { - // The source value may be an integer, or a pointer. - if (isa(Src->getType())) - return Builder.CreateBitCast(Src, DstTy, "conv"); - assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); - return Builder.CreateIntToPtr(Src, DstTy, "conv"); - } - - if (isa(SrcType)) { - // Must be an ptr to int cast. - assert(isa(DstTy) && "not ptr->int?"); - return Builder.CreatePtrToInt(Src, DstTy, "conv"); - } - - // A scalar source can be splatted to an OCU vector of the same element type - if (DstType->isOCUVectorType() && !isa(SrcType) && - cast(DstTy)->getElementType() == Src->getType()) - return CGF.EmitVector(&Src, DstType->getAsVectorType()->getNumElements(), - true); - - // Allow bitcast from vector to integer/fp of the same size. - if (isa(Src->getType()) || - isa(DstTy)) - return Builder.CreateBitCast(Src, DstTy, "conv"); - - // Finally, we have the arithmetic types: real int/float. - if (isa(Src->getType())) { - bool InputSigned = SrcType->isSignedIntegerType(); - if (isa(DstTy)) - return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); - else if (InputSigned) - return Builder.CreateSIToFP(Src, DstTy, "conv"); - else - return Builder.CreateUIToFP(Src, DstTy, "conv"); - } - - assert(Src->getType()->isFloatingPoint() && "Unknown real conversion"); - if (isa(DstTy)) { - if (DstType->isSignedIntegerType()) - return Builder.CreateFPToSI(Src, DstTy, "conv"); - else - return Builder.CreateFPToUI(Src, DstTy, "conv"); - } - - assert(DstTy->isFloatingPoint() && "Unknown real conversion"); - if (DstTy->getTypeID() < Src->getType()->getTypeID()) - return Builder.CreateFPTrunc(Src, DstTy, "conv"); - else - return Builder.CreateFPExt(Src, DstTy, "conv"); -} - -/// EmitComplexToScalarConversion - Emit a conversion from the specified -/// complex type to the specified destination type, where the destination -/// type is an LLVM scalar type. -Value *ScalarExprEmitter:: -EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, - QualType SrcTy, QualType DstTy) { - // Get the source element type. - SrcTy = cast(SrcTy.getCanonicalType())->getElementType(); - - // Handle conversions to bool first, they are special: comparisons against 0. - if (DstTy->isBooleanType()) { - // Complex != 0 -> (Real != 0) | (Imag != 0) - Src.first = EmitScalarConversion(Src.first, SrcTy, DstTy); - Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy); - return Builder.CreateOr(Src.first, Src.second, "tobool"); - } - - // C99 6.3.1.7p2: "When a value of complex type is converted to a real type, - // the imaginary part of the complex value is discarded and the value of the - // real part is converted according to the conversion rules for the - // corresponding real type. - return EmitScalarConversion(Src.first, SrcTy, DstTy); -} - - -//===----------------------------------------------------------------------===// -// Visitor Methods -//===----------------------------------------------------------------------===// - -Value *ScalarExprEmitter::VisitExpr(Expr *E) { - CGF.WarnUnsupported(E, "scalar expression"); - if (E->getType()->isVoidType()) - return 0; - return llvm::UndefValue::get(CGF.ConvertType(E->getType())); -} - -Value *ScalarExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { - // Only the lookup mechanism and first two arguments of the method - // implementation vary between runtimes. We can get the receiver and - // arguments in generic code. - - // Find the receiver - llvm::Value * Receiver = CGF.EmitScalarExpr(E->getReceiver()); - - // Process the arguments - unsigned int ArgC = E->getNumArgs(); - llvm::SmallVector Args; - for(unsigned i=0 ; igetArg(i); - QualType ArgTy = ArgExpr->getType(); - if (!CGF.hasAggregateLLVMType(ArgTy)) { - // Scalar argument is passed by-value. - Args.push_back(CGF.EmitScalarExpr(ArgExpr)); - } else if (ArgTy->isComplexType()) { - // Make a temporary alloca to pass the argument. - llvm::Value *DestMem = CGF.CreateTempAlloca(ConvertType(ArgTy)); - CGF.EmitComplexExprIntoAddr(ArgExpr, DestMem, false); - Args.push_back(DestMem); - } else { - llvm::Value *DestMem = CGF.CreateTempAlloca(ConvertType(ArgTy)); - CGF.EmitAggExpr(ArgExpr, DestMem, false); - Args.push_back(DestMem); - } - } - - // Get the selector string - std::string SelStr = E->getSelector().getName(); - llvm::Constant *Selector = CGF.CGM.GetAddrOfConstantString(SelStr); - ConvertType(E->getType()); - return Runtime->generateMessageSend(Builder, - ConvertType(E->getType()), - Receiver, - Selector, - &Args[0], - Args.size()); -} - -Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { - // Emit subscript expressions in rvalue context's. For most cases, this just - // loads the lvalue formed by the subscript expr. However, we have to be - // careful, because the base of a vector subscript is occasionally an rvalue, - // so we can't get it as an lvalue. - if (!E->getBase()->getType()->isVectorType()) - return EmitLoadOfLValue(E); - - // Handle the vector case. The base must be a vector, the index must be an - // integer value. - Value *Base = Visit(E->getBase()); - Value *Idx = Visit(E->getIdx()); - - // FIXME: Convert Idx to i32 type. - return Builder.CreateExtractElement(Base, Idx, "vecext"); -} - -/// VisitImplicitCastExpr - Implicit casts are the same as normal casts, but -/// also handle things like function to pointer-to-function decay, and array to -/// pointer decay. -Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) { - const Expr *Op = E->getSubExpr(); - - // If this is due to array->pointer conversion, emit the array expression as - // an l-value. - if (Op->getType()->isArrayType()) { - // FIXME: For now we assume that all source arrays map to LLVM arrays. This - // will not true when we add support for VLAs. - Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays. - - assert(isa(V->getType()) && - isa(cast(V->getType()) - ->getElementType()) && - "Doesn't support VLAs yet!"); - llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - - llvm::Value *Ops[] = {Idx0, Idx0}; - V = Builder.CreateGEP(V, Ops, Ops+2, "arraydecay"); - - // The resultant pointer type can be implicitly casted to other pointer - // types as well, for example void*. - const llvm::Type *DestPTy = ConvertType(E->getType()); - assert(isa(DestPTy) && - "Only expect implicit cast to pointer"); - if (V->getType() != DestPTy) - V = Builder.CreateBitCast(V, DestPTy, "ptrconv"); - return V; - - } else if (E->getType()->isReferenceType()) { - assert(cast(E->getType().getCanonicalType())-> - getReferenceeType() == - Op->getType().getCanonicalType() && "Incompatible types!"); - - return EmitLValue(Op).getAddress(); - } - - return EmitCastExpr(Op, E->getType()); -} - - -// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts -// have to handle a more broad range of conversions than explicit casts, as they -// handle things like function to ptr-to-function decay etc. -Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) { - // Handle cases where the source is an non-complex type. - - if (!CGF.hasAggregateLLVMType(E->getType())) { - Value *Src = Visit(const_cast(E)); - - // Use EmitScalarConversion to perform the conversion. - return EmitScalarConversion(Src, E->getType(), DestTy); - } - - if (E->getType()->isComplexType()) { - // Handle cases where the source is a complex type. - return EmitComplexToScalarConversion(CGF.EmitComplexExpr(E), E->getType(), - DestTy); - } - - // Okay, this is a cast from an aggregate. It must be a cast to void. Just - // evaluate the result and return. - CGF.EmitAggExpr(E, 0, false); - return 0; -} - -Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { - return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getScalarVal(); -} - - -//===----------------------------------------------------------------------===// -// Unary Operators -//===----------------------------------------------------------------------===// - -Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, - bool isInc, bool isPre) { - LValue LV = EmitLValue(E->getSubExpr()); - // FIXME: Handle volatile! - Value *InVal = CGF.EmitLoadOfLValue(LV, // false - E->getSubExpr()->getType()).getScalarVal(); - - int AmountVal = isInc ? 1 : -1; - - Value *NextVal; - if (isa(InVal->getType())) { - // FIXME: This isn't right for VLAs. - NextVal = llvm::ConstantInt::get(llvm::Type::Int32Ty, AmountVal); - NextVal = Builder.CreateGEP(InVal, NextVal); - } else { - // Add the inc/dec to the real part. - if (isa(InVal->getType())) - NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); - else if (InVal->getType() == llvm::Type::FloatTy) - // FIXME: Handle long double. - NextVal = - llvm::ConstantFP::get(InVal->getType(), - llvm::APFloat(static_cast(AmountVal))); - else { - // FIXME: Handle long double. - assert(InVal->getType() == llvm::Type::DoubleTy); - NextVal = - llvm::ConstantFP::get(InVal->getType(), - llvm::APFloat(static_cast(AmountVal))); - } - NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); - } - - // Store the updated result through the lvalue. - CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, - E->getSubExpr()->getType()); - - // If this is a postinc, return the value read from memory, otherwise use the - // updated value. - return isPre ? NextVal : InVal; -} - - -Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { - Value *Op = Visit(E->getSubExpr()); - return Builder.CreateNeg(Op, "neg"); -} - -Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) { - Value *Op = Visit(E->getSubExpr()); - return Builder.CreateNot(Op, "neg"); -} - -Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { - // Compare operand to zero. - Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr()); - - // Invert value. - // TODO: Could dynamically modify easy computations here. For example, if - // the operand is an icmp ne, turn into icmp eq. - BoolVal = Builder.CreateNot(BoolVal, "lnot"); - - // ZExt result to int. - return Builder.CreateZExt(BoolVal, CGF.LLVMIntTy, "lnot.ext"); -} - -/// EmitSizeAlignOf - Return the size or alignment of the 'TypeToSize' type as -/// an integer (RetType). -Value *ScalarExprEmitter::EmitSizeAlignOf(QualType TypeToSize, - QualType RetType,bool isSizeOf){ - assert(RetType->isIntegerType() && "Result type must be an integer!"); - uint32_t ResultWidth = - static_cast(CGF.getContext().getTypeSize(RetType)); - - // sizeof(void) and __alignof__(void) = 1 as a gcc extension. - if (TypeToSize->isVoidType()) - return llvm::ConstantInt::get(llvm::APInt(ResultWidth, 1)); - - /// FIXME: This doesn't handle VLAs yet! - std::pair Info = CGF.getContext().getTypeInfo(TypeToSize); - - uint64_t Val = isSizeOf ? Info.first : Info.second; - Val /= 8; // Return size in bytes, not bits. - - return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); -} - -Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) { - Expr *Op = E->getSubExpr(); - if (Op->getType()->isComplexType()) - return CGF.EmitComplexExpr(Op).first; - return Visit(Op); -} -Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { - Expr *Op = E->getSubExpr(); - if (Op->getType()->isComplexType()) - return CGF.EmitComplexExpr(Op).second; - - // __imag on a scalar returns zero. Emit it the subexpr to ensure side - // effects are evaluated. - CGF.EmitScalarExpr(Op); - return llvm::Constant::getNullValue(ConvertType(E->getType())); -} - -Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) -{ - int64_t Val = E->evaluateOffsetOf(CGF.getContext()); - - assert(E->getType()->isIntegerType() && "Result type must be an integer!"); - - uint32_t ResultWidth = - static_cast(CGF.getContext().getTypeSize(E->getType())); - return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); -} - -//===----------------------------------------------------------------------===// -// Binary Operators -//===----------------------------------------------------------------------===// - -BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { - BinOpInfo Result; - Result.LHS = Visit(E->getLHS()); - Result.RHS = Visit(E->getRHS()); - Result.Ty = E->getType(); - Result.E = E; - return Result; -} - -Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, - Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { - QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType(); - - BinOpInfo OpInfo; - - // Load the LHS and RHS operands. - LValue LHSLV = EmitLValue(E->getLHS()); - OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); - - // Determine the computation type. If the RHS is complex, then this is one of - // the add/sub/mul/div operators. All of these operators can be computed in - // with just their real component even though the computation domain really is - // complex. - QualType ComputeType = E->getComputationType(); - - // If the computation type is complex, then the RHS is complex. Emit the RHS. - if (const ComplexType *CT = ComputeType->getAsComplexType()) { - ComputeType = CT->getElementType(); - - // Emit the RHS, only keeping the real component. - OpInfo.RHS = CGF.EmitComplexExpr(E->getRHS()).first; - RHSTy = RHSTy->getAsComplexType()->getElementType(); - } else { - // Otherwise the RHS is a simple scalar value. - OpInfo.RHS = Visit(E->getRHS()); - } - - // Convert the LHS/RHS values to the computation type. - OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, ComputeType); - - // Do not merge types for -= or += where the LHS is a pointer. - if (!(E->getOpcode() == BinaryOperator::SubAssign || - E->getOpcode() == BinaryOperator::AddAssign) || - !E->getLHS()->getType()->isPointerType()) { - OpInfo.RHS = EmitScalarConversion(OpInfo.RHS, RHSTy, ComputeType); - } - OpInfo.Ty = ComputeType; - OpInfo.E = E; - - // Expand the binary operator. - Value *Result = (this->*Func)(OpInfo); - - // Truncate the result back to the LHS type. - Result = EmitScalarConversion(Result, ComputeType, LHSTy); - - // Store the result value into the LHS lvalue. - CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, E->getType()); - - return Result; -} - - -Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { - if (Ops.LHS->getType()->isFPOrFPVector()) - return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); - else if (Ops.Ty->isUnsignedIntegerType()) - return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div"); - else - return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div"); -} - -Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { - // Rem in C can't be a floating point type: C99 6.5.5p2. - if (Ops.Ty->isUnsignedIntegerType()) - return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); - else - return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); -} - - -Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { - if (!Ops.Ty->isPointerType()) - return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); - - // FIXME: What about a pointer to a VLA? - Value *Ptr, *Idx; - Expr *IdxExp; - if (isa(Ops.LHS->getType())) { // pointer + int - Ptr = Ops.LHS; - Idx = Ops.RHS; - IdxExp = Ops.E->getRHS(); - } else { // int + pointer - Ptr = Ops.RHS; - Idx = Ops.LHS; - IdxExp = Ops.E->getLHS(); - } - - unsigned Width = cast(Idx->getType())->getBitWidth(); - if (Width < CGF.LLVMPointerWidth) { - // Zero or sign extend the pointer value based on whether the index is - // signed or not. - const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth); - if (IdxExp->getType().getCanonicalType()->isSignedIntegerType()) - Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); - else - Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); - } - - return Builder.CreateGEP(Ptr, Idx, "add.ptr"); -} - -Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { - if (!isa(Ops.LHS->getType())) - return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); - - // pointer - int - assert(!isa(Ops.RHS->getType()) && - "ptr-ptr shouldn't get here"); - // FIXME: The pointer could point to a VLA. - Value *Idx = Builder.CreateNeg(Ops.RHS, "sub.ptr.neg"); - - unsigned Width = cast(Idx->getType())->getBitWidth(); - if (Width < CGF.LLVMPointerWidth) { - // Zero or sign extend the pointer value based on whether the index is - // signed or not. - const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth); - if (Ops.E->getRHS()->getType().getCanonicalType()->isSignedIntegerType()) - Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); - else - Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); - } - - return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr"); -} - -Value *ScalarExprEmitter::VisitBinSub(const BinaryOperator *E) { - // "X - Y" is different from "X -= Y" in one case: when Y is a pointer. In - // the compound assignment case it is invalid, so just handle it here. - if (!E->getRHS()->getType()->isPointerType()) - return EmitSub(EmitBinOps(E)); - - // pointer - pointer - Value *LHS = Visit(E->getLHS()); - Value *RHS = Visit(E->getRHS()); - - const QualType LHSType = E->getLHS()->getType().getCanonicalType(); - const QualType LHSElementType = cast(LHSType)->getPointeeType(); - uint64_t ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8; - - const llvm::Type *ResultType = ConvertType(E->getType()); - LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast"); - RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); - Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); - - // HACK: LLVM doesn't have an divide instruction that 'knows' there is no - // remainder. As such, we handle common power-of-two cases here to generate - // better code. - if (llvm::isPowerOf2_64(ElementSize)) { - Value *ShAmt = - llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize)); - return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr"); - } - - // Otherwise, do a full sdiv. - Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize); - return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); -} - - -Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { - // LLVM requires the LHS and RHS to be the same type: promote or truncate the - // RHS to the same size as the LHS. - Value *RHS = Ops.RHS; - if (Ops.LHS->getType() != RHS->getType()) - RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - - return Builder.CreateShl(Ops.LHS, RHS, "shl"); -} - -Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { - // LLVM requires the LHS and RHS to be the same type: promote or truncate the - // RHS to the same size as the LHS. - Value *RHS = Ops.RHS; - if (Ops.LHS->getType() != RHS->getType()) - RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - - if (Ops.Ty->isUnsignedIntegerType()) - return Builder.CreateLShr(Ops.LHS, RHS, "shr"); - return Builder.CreateAShr(Ops.LHS, RHS, "shr"); -} - -Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, - unsigned SICmpOpc, unsigned FCmpOpc) { - Value *Result; - QualType LHSTy = E->getLHS()->getType(); - if (!LHSTy->isComplexType()) { - Value *LHS = Visit(E->getLHS()); - Value *RHS = Visit(E->getRHS()); - - if (LHS->getType()->isFloatingPoint()) { - Result = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, - LHS, RHS, "cmp"); - } else if (LHSTy->isUnsignedIntegerType()) { - Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHS, RHS, "cmp"); - } else { - // Signed integers and pointers. - Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc, - LHS, RHS, "cmp"); - } - } else { - // Complex Comparison: can only be an equality comparison. - CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS()); - CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS()); - - QualType CETy = - cast(LHSTy.getCanonicalType())->getElementType(); - - Value *ResultR, *ResultI; - if (CETy->isRealFloatingType()) { - ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, - LHS.first, RHS.first, "cmp.r"); - ResultI = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, - LHS.second, RHS.second, "cmp.i"); - } else { - // Complex comparisons can only be equality comparisons. As such, signed - // and unsigned opcodes are the same. - ResultR = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHS.first, RHS.first, "cmp.r"); - ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHS.second, RHS.second, "cmp.i"); - } - - if (E->getOpcode() == BinaryOperator::EQ) { - Result = Builder.CreateAnd(ResultR, ResultI, "and.ri"); - } else { - assert(E->getOpcode() == BinaryOperator::NE && - "Complex comparison other than == or != ?"); - Result = Builder.CreateOr(ResultR, ResultI, "or.ri"); - } - } - - // ZExt result to int. - return Builder.CreateZExt(Result, CGF.LLVMIntTy, "cmp.ext"); -} - -Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { - LValue LHS = EmitLValue(E->getLHS()); - Value *RHS = Visit(E->getRHS()); - - // Store the value into the LHS. - // FIXME: Volatility! - CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType()); - - // Return the RHS. - return RHS; -} - -Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { - Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS()); - - llvm::BasicBlock *ContBlock = new llvm::BasicBlock("land_cont"); - llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("land_rhs"); - - llvm::BasicBlock *OrigBlock = Builder.GetInsertBlock(); - Builder.CreateCondBr(LHSCond, RHSBlock, ContBlock); - - CGF.EmitBlock(RHSBlock); - Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - - // Reaquire the RHS block, as there may be subblocks inserted. - RHSBlock = Builder.GetInsertBlock(); - CGF.EmitBlock(ContBlock); - - // Create a PHI node. If we just evaluted the LHS condition, the result is - // false. If we evaluated both, the result is the RHS condition. - llvm::PHINode *PN = Builder.CreatePHI(llvm::Type::Int1Ty, "land"); - PN->reserveOperandSpace(2); - PN->addIncoming(llvm::ConstantInt::getFalse(), OrigBlock); - PN->addIncoming(RHSCond, RHSBlock); - - // ZExt result to int. - return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext"); -} - -Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { - Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS()); - - llvm::BasicBlock *ContBlock = new llvm::BasicBlock("lor_cont"); - llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("lor_rhs"); - - llvm::BasicBlock *OrigBlock = Builder.GetInsertBlock(); - Builder.CreateCondBr(LHSCond, ContBlock, RHSBlock); - - CGF.EmitBlock(RHSBlock); - Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - - // Reaquire the RHS block, as there may be subblocks inserted. - RHSBlock = Builder.GetInsertBlock(); - CGF.EmitBlock(ContBlock); - - // Create a PHI node. If we just evaluted the LHS condition, the result is - // true. If we evaluated both, the result is the RHS condition. - llvm::PHINode *PN = Builder.CreatePHI(llvm::Type::Int1Ty, "lor"); - PN->reserveOperandSpace(2); - PN->addIncoming(llvm::ConstantInt::getTrue(), OrigBlock); - PN->addIncoming(RHSCond, RHSBlock); - - // ZExt result to int. - return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext"); -} - -Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { - CGF.EmitStmt(E->getLHS()); - return Visit(E->getRHS()); -} - -//===----------------------------------------------------------------------===// -// Other Operators -//===----------------------------------------------------------------------===// - -Value *ScalarExprEmitter:: -VisitConditionalOperator(const ConditionalOperator *E) { - llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?"); - llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:"); - llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont"); - - // Evaluate the conditional, then convert it to bool. We do this explicitly - // because we need the unconverted value if this is a GNU ?: expression with - // missing middle value. - Value *CondVal = CGF.EmitScalarExpr(E->getCond()); - Value *CondBoolVal =CGF.EmitScalarConversion(CondVal, E->getCond()->getType(), - CGF.getContext().BoolTy); - Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); - - CGF.EmitBlock(LHSBlock); - - // Handle the GNU extension for missing LHS. - Value *LHS; - if (E->getLHS()) - LHS = Visit(E->getLHS()); - else // Perform promotions, to handle cases like "short ?: int" - LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType()); - - Builder.CreateBr(ContBlock); - LHSBlock = Builder.GetInsertBlock(); - - CGF.EmitBlock(RHSBlock); - - Value *RHS = Visit(E->getRHS()); - Builder.CreateBr(ContBlock); - RHSBlock = Builder.GetInsertBlock(); - - CGF.EmitBlock(ContBlock); - - if (!LHS) { - assert(E->getType()->isVoidType() && "Non-void value should have a value"); - return 0; - } - - // Create a PHI node for the real part. - llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); - PN->reserveOperandSpace(2); - PN->addIncoming(LHS, LHSBlock); - PN->addIncoming(RHS, RHSBlock); - return PN; -} - -Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { - // Emit the LHS or RHS as appropriate. - return - Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() : E->getRHS()); -} - -Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) { - return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), - E->getNumArgs(CGF.getContext())).getScalarVal(); -} - -Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { - llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress(); - - llvm::Value *V = Builder.CreateVAArg(ArgValue, ConvertType(VE->getType())); - return V; -} - -Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { - std::string str; - llvm::SmallVector EncodingRecordTypes; - CGF.getContext().getObjCEncodingForType(E->getEncodedType(), str, - EncodingRecordTypes); - - llvm::Constant *C = llvm::ConstantArray::get(str); - C = new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, ".str", &CGF.CGM.getModule()); - llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); - llvm::Constant *Zeros[] = { Zero, Zero }; - C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2); - - return C; -} - -//===----------------------------------------------------------------------===// -// Entry Point into this File -//===----------------------------------------------------------------------===// - -/// EmitComplexExpr - Emit the computation of the specified expression of -/// complex type, ignoring the result. -Value *CodeGenFunction::EmitScalarExpr(const Expr *E) { - assert(E && !hasAggregateLLVMType(E->getType()) && - "Invalid scalar expression to emit"); - - return ScalarExprEmitter(*this).Visit(const_cast(E)); -} - -/// EmitScalarConversion - Emit a conversion from the specified type to the -/// specified destination type, both of which are LLVM scalar types. -Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy, - QualType DstTy) { - assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) && - "Invalid scalar expression to emit"); - return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy); -} - -/// EmitComplexToScalarConversion - Emit a conversion from the specified -/// complex type to the specified destination type, where the destination -/// type is an LLVM scalar type. -Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src, - QualType SrcTy, - QualType DstTy) { - assert(SrcTy->isComplexType() && !hasAggregateLLVMType(DstTy) && - "Invalid complex -> scalar conversion"); - return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy, - DstTy); -} - -Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) { - assert(V1->getType() == V2->getType() && - "Vector operands must be of the same type"); - - unsigned NumElements = - cast(V1->getType())->getNumElements(); - - va_list va; - va_start(va, V2); - - llvm::SmallVector Args; - - for (unsigned i = 0; i < NumElements; i++) { - int n = va_arg(va, int); - - assert(n >= 0 && n < (int)NumElements * 2 && - "Vector shuffle index out of bounds!"); - - Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, n)); - } - - const char *Name = va_arg(va, const char *); - va_end(va); - - llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); - - return Builder.CreateShuffleVector(V1, V2, Mask, Name); -} - -llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, - unsigned NumVals, bool isSplat) -{ - llvm::Value *Vec - = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals)); - - for (unsigned i = 0, e = NumVals ; i != e; ++i) { - llvm::Value *Val = isSplat ? Vals[0] : Vals[i]; - llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); - Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp"); - } - - return Vec; -} diff --git a/clang/CodeGen/CGObjC.cpp b/clang/CodeGen/CGObjC.cpp deleted file mode 100644 index 33419a3d51d..00000000000 --- a/clang/CodeGen/CGObjC.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Objective-C code as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/AST/Expr.h" -#include "llvm/Constant.h" -using namespace clang; -using namespace CodeGen; - -llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){ - std::string S(E->getString()->getStrData(), E->getString()->getByteLength()); - return CGM.GetAddrOfConstantCFString(S); -} - diff --git a/clang/CodeGen/CGObjCGNU.cpp b/clang/CodeGen/CGObjCGNU.cpp deleted file mode 100644 index f0d6f554d55..00000000000 --- a/clang/CodeGen/CGObjCGNU.cpp +++ /dev/null @@ -1,97 +0,0 @@ -//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This provides Objective-C code generation targetting the GNU runtime. -// -//===----------------------------------------------------------------------===// - -#include "CGObjCRuntime.h" -#include "llvm/Module.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/LLVMBuilder.h" -#include "llvm/ADT/SmallVector.h" - -using namespace clang::CodeGen; -using namespace clang; - -CGObjCRuntime::~CGObjCRuntime() {} - -namespace { -class CGObjCGNU : public CGObjCRuntime { -private: - llvm::Module &TheModule; -public: - CGObjCGNU(llvm::Module &M) : TheModule(M) {}; - virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder, - const llvm::Type *ReturnTy, - llvm::Value *Receiver, - llvm::Constant *Selector, - llvm::Value** ArgV, - unsigned ArgC); -}; -} // end anonymous namespace - -// Generate code for a message send expression on the GNU runtime. -// BIG FAT WARNING: Much of this code will need factoring out later. -// FIXME: This currently only handles id returns. Other return types -// need some explicit casting. -llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder, - const llvm::Type *ReturnTy, - llvm::Value *Receiver, - llvm::Constant *Selector, - llvm::Value** ArgV, - unsigned ArgC) { - // Get the selector Type. - const llvm::Type *PtrToInt8Ty = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - std::vector Str2(2, PtrToInt8Ty); - const llvm::Type *SelStructTy = llvm::StructType::get(Str2); - const llvm::Type *SelTy = llvm::PointerType::getUnqual(SelStructTy); - - // Look up the selector. - // If we haven't got the selector lookup function, look it up now. - // TODO: Factor this out and use it to implement @selector() too. - llvm::Constant *SelFunction = - TheModule.getOrInsertFunction("sel_get_uid", SelTy, PtrToInt8Ty, NULL); - // FIXME: Selectors should be statically cached, not looked up on every call. - - // TODO: Pull this out into the caller. - llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); - llvm::Constant *Ops[] = {Idx0, Idx0}; - llvm::Value *SelStr = llvm::ConstantExpr::getGetElementPtr(Selector, Ops, 2); - llvm::Value *cmd = Builder.CreateCall(SelFunction, &SelStr, &SelStr+1); - - // Look up the method implementation. - std::vector impArgTypes; - impArgTypes.push_back(Receiver->getType()); - impArgTypes.push_back(SelTy); - - // Avoid an explicit cast on the IMP by getting a version that has the right - // return type. - llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes, - true); - - llvm::Constant *lookupFunction = - TheModule.getOrInsertFunction("objc_msg_lookup", - llvm::PointerType::get(impType, 0), - Receiver->getType(), SelTy, NULL); - llvm::SmallVector lookupArgs; - lookupArgs.push_back(Receiver); - lookupArgs.push_back(cmd); - llvm::Value *imp = Builder.CreateCall(lookupFunction, - lookupArgs.begin(), lookupArgs.end()); - - // Call the method. - lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC); - return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end()); -} - -CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(llvm::Module &M) { - return new CGObjCGNU(M); -} diff --git a/clang/CodeGen/CGObjCRuntime.h b/clang/CodeGen/CGObjCRuntime.h deleted file mode 100644 index d8fc60f99c0..00000000000 --- a/clang/CodeGen/CGObjCRuntime.h +++ /dev/null @@ -1,47 +0,0 @@ -//===----- CGObjCRuntime.h - Emit LLVM Code from ASTs for a Module --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This provides an abstract class for Objective-C code generation. Concrete -// subclasses of this implement code generation for specific Objective-C -// runtime libraries. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_OBCJRUNTIME_H -#define CLANG_CODEGEN_OBCJRUNTIME_H - -namespace llvm { - class LLVMFoldingBuilder; - class Constant; - class Type; - class Value; - class Module; -} - -namespace clang { -namespace CodeGen { - -// Implements runtime-specific code generation functions -class CGObjCRuntime { -public: - virtual ~CGObjCRuntime(); - - // Generate an Objective-C message send operation - virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder, - const llvm::Type *ReturnTy, - llvm::Value *Receiver, - llvm::Constant *Selector, - llvm::Value** ArgV, - unsigned ArgC) = 0; -}; - -CGObjCRuntime *CreateObjCRuntime(llvm::Module &M); -} -} -#endif diff --git a/clang/CodeGen/CGStmt.cpp b/clang/CodeGen/CGStmt.cpp deleted file mode 100644 index 5fdc61b46f8..00000000000 --- a/clang/CodeGen/CGStmt.cpp +++ /dev/null @@ -1,776 +0,0 @@ -//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit Stmt nodes as LLVM code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "clang/AST/AST.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/InlineAsm.h" -#include "llvm/ADT/StringExtras.h" -using namespace clang; -using namespace CodeGen; - -//===----------------------------------------------------------------------===// -// Statement Emission -//===----------------------------------------------------------------------===// - -void CodeGenFunction::EmitStmt(const Stmt *S) { - assert(S && "Null statement?"); - - switch (S->getStmtClass()) { - default: - // Must be an expression in a stmt context. Emit the value (to get - // side-effects) and ignore the result. - if (const Expr *E = dyn_cast(S)) { - if (!hasAggregateLLVMType(E->getType())) - EmitScalarExpr(E); - else if (E->getType()->isComplexType()) - EmitComplexExpr(E); - else - EmitAggExpr(E, 0, false); - } else { - WarnUnsupported(S, "statement"); - } - break; - case Stmt::NullStmtClass: break; - case Stmt::CompoundStmtClass: EmitCompoundStmt(cast(*S)); break; - case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; - case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; - - case Stmt::IfStmtClass: EmitIfStmt(cast(*S)); break; - case Stmt::WhileStmtClass: EmitWhileStmt(cast(*S)); break; - case Stmt::DoStmtClass: EmitDoStmt(cast(*S)); break; - case Stmt::ForStmtClass: EmitForStmt(cast(*S)); break; - - case Stmt::ReturnStmtClass: EmitReturnStmt(cast(*S)); break; - case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; - - case Stmt::BreakStmtClass: EmitBreakStmt(); break; - case Stmt::ContinueStmtClass: EmitContinueStmt(); break; - case Stmt::SwitchStmtClass: EmitSwitchStmt(cast(*S)); break; - case Stmt::DefaultStmtClass: EmitDefaultStmt(cast(*S)); break; - case Stmt::CaseStmtClass: EmitCaseStmt(cast(*S)); break; - case Stmt::AsmStmtClass: EmitAsmStmt(cast(*S)); break; - } -} - -/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true, -/// this captures the expression result of the last sub-statement and returns it -/// (for use by the statement expression extension). -RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, - llvm::Value *AggLoc, bool isAggVol) { - // FIXME: handle vla's etc. - if (S.body_empty() || !isa(S.body_back())) GetLast = false; - - for (CompoundStmt::const_body_iterator I = S.body_begin(), - E = S.body_end()-GetLast; I != E; ++I) - EmitStmt(*I); - - - if (!GetLast) - return RValue::get(0); - - return EmitAnyExpr(cast(S.body_back()), AggLoc); -} - -void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB) { - // Emit a branch from this block to the next one if this was a real block. If - // this was just a fall-through block after a terminator, don't emit it. - llvm::BasicBlock *LastBB = Builder.GetInsertBlock(); - - if (LastBB->getTerminator()) { - // If the previous block is already terminated, don't touch it. - } else if (LastBB->empty() && LastBB->getValueName() == 0) { - // If the last block was an empty placeholder, remove it now. - // TODO: cache and reuse these. - Builder.GetInsertBlock()->eraseFromParent(); - } else { - // Otherwise, create a fall-through branch. - Builder.CreateBr(BB); - } - CurFn->getBasicBlockList().push_back(BB); - Builder.SetInsertPoint(BB); -} - -void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { - llvm::BasicBlock *NextBB = getBasicBlockForLabel(&S); - - EmitBlock(NextBB); - EmitStmt(S.getSubStmt()); -} - -void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { - Builder.CreateBr(getBasicBlockForLabel(S.getLabel())); - - // Emit a block after the branch so that dead code after a goto has some place - // to go. - Builder.SetInsertPoint(new llvm::BasicBlock("", CurFn)); -} - -void CodeGenFunction::EmitIfStmt(const IfStmt &S) { - // C99 6.8.4.1: The first substatement is executed if the expression compares - // unequal to 0. The condition must be a scalar type. - llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - - llvm::BasicBlock *ContBlock = new llvm::BasicBlock("ifend"); - llvm::BasicBlock *ThenBlock = new llvm::BasicBlock("ifthen"); - llvm::BasicBlock *ElseBlock = ContBlock; - - if (S.getElse()) - ElseBlock = new llvm::BasicBlock("ifelse"); - - // Insert the conditional branch. - Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock); - - // Emit the 'then' code. - EmitBlock(ThenBlock); - EmitStmt(S.getThen()); - llvm::BasicBlock *BB = Builder.GetInsertBlock(); - if (isDummyBlock(BB)) { - BB->eraseFromParent(); - Builder.SetInsertPoint(ThenBlock); - } - else - Builder.CreateBr(ContBlock); - - // Emit the 'else' code if present. - if (const Stmt *Else = S.getElse()) { - EmitBlock(ElseBlock); - EmitStmt(Else); - llvm::BasicBlock *BB = Builder.GetInsertBlock(); - if (isDummyBlock(BB)) { - BB->eraseFromParent(); - Builder.SetInsertPoint(ElseBlock); - } - else - Builder.CreateBr(ContBlock); - } - - // Emit the continuation block for code after the if. - EmitBlock(ContBlock); -} - -void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { - // Emit the header for the loop, insert it, which will create an uncond br to - // it. - llvm::BasicBlock *LoopHeader = new llvm::BasicBlock("whilecond"); - EmitBlock(LoopHeader); - - // Evaluate the conditional in the while header. C99 6.8.5.1: The evaluation - // of the controlling expression takes place before each execution of the loop - // body. - llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - - // while(1) is common, avoid extra exit blocks. Be sure - // to correctly handle break/continue though. - bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) - if (C->isOne()) - EmitBoolCondBranch = false; - - // Create an exit block for when the condition fails, create a block for the - // body of the loop. - llvm::BasicBlock *ExitBlock = new llvm::BasicBlock("whileexit"); - llvm::BasicBlock *LoopBody = new llvm::BasicBlock("whilebody"); - - // As long as the condition is true, go to the loop body. - if (EmitBoolCondBranch) - Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); - - // Store the blocks to use for break and continue. - BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader)); - - // Emit the loop body. - EmitBlock(LoopBody); - EmitStmt(S.getBody()); - - BreakContinueStack.pop_back(); - - // Cycle to the condition. - Builder.CreateBr(LoopHeader); - - // Emit the exit block. - EmitBlock(ExitBlock); - - // If LoopHeader is a simple forwarding block then eliminate it. - if (!EmitBoolCondBranch - && &LoopHeader->front() == LoopHeader->getTerminator()) { - LoopHeader->replaceAllUsesWith(LoopBody); - LoopHeader->getTerminator()->eraseFromParent(); - LoopHeader->eraseFromParent(); - } -} - -void CodeGenFunction::EmitDoStmt(const DoStmt &S) { - // Emit the body for the loop, insert it, which will create an uncond br to - // it. - llvm::BasicBlock *LoopBody = new llvm::BasicBlock("dobody"); - llvm::BasicBlock *AfterDo = new llvm::BasicBlock("afterdo"); - EmitBlock(LoopBody); - - llvm::BasicBlock *DoCond = new llvm::BasicBlock("docond"); - - // Store the blocks to use for break and continue. - BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond)); - - // Emit the body of the loop into the block. - EmitStmt(S.getBody()); - - BreakContinueStack.pop_back(); - - EmitBlock(DoCond); - - // C99 6.8.5.2: "The evaluation of the controlling expression takes place - // after each execution of the loop body." - - // Evaluate the conditional in the while header. - // C99 6.8.5p2/p4: The first substatement is executed if the expression - // compares unequal to 0. The condition must be a scalar type. - llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - - // "do {} while (0)" is common in macros, avoid extra blocks. Be sure - // to correctly handle break/continue though. - bool EmitBoolCondBranch = true; - if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) - if (C->isZero()) - EmitBoolCondBranch = false; - - // As long as the condition is true, iterate the loop. - if (EmitBoolCondBranch) - Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo); - - // Emit the exit block. - EmitBlock(AfterDo); - - // If DoCond is a simple forwarding block then eliminate it. - if (!EmitBoolCondBranch && &DoCond->front() == DoCond->getTerminator()) { - DoCond->replaceAllUsesWith(AfterDo); - DoCond->getTerminator()->eraseFromParent(); - DoCond->eraseFromParent(); - } -} - -void CodeGenFunction::EmitForStmt(const ForStmt &S) { - // FIXME: What do we do if the increment (f.e.) contains a stmt expression, - // which contains a continue/break? - // TODO: We could keep track of whether the loop body contains any - // break/continue statements and not create unnecessary blocks (like - // "afterfor" for a condless loop) if it doesn't. - - // Evaluate the first part before the loop. - if (S.getInit()) - EmitStmt(S.getInit()); - - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = new llvm::BasicBlock("forcond"); - llvm::BasicBlock *AfterFor = new llvm::BasicBlock("afterfor"); - - EmitBlock(CondBlock); - - // Evaluate the condition if present. If not, treat it as a non-zero-constant - // according to 6.8.5.3p2, aka, true. - if (S.getCond()) { - // C99 6.8.5p2/p4: The first substatement is executed if the expression - // compares unequal to 0. The condition must be a scalar type. - llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - - // As long as the condition is true, iterate the loop. - llvm::BasicBlock *ForBody = new llvm::BasicBlock("forbody"); - Builder.CreateCondBr(BoolCondVal, ForBody, AfterFor); - EmitBlock(ForBody); - } else { - // Treat it as a non-zero constant. Don't even create a new block for the - // body, just fall into it. - } - - // If the for loop doesn't have an increment we can just use the - // condition as the continue block. - llvm::BasicBlock *ContinueBlock; - if (S.getInc()) - ContinueBlock = new llvm::BasicBlock("forinc"); - else - ContinueBlock = CondBlock; - - // Store the blocks to use for break and continue. - BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock)); - - // If the condition is true, execute the body of the for stmt. - EmitStmt(S.getBody()); - - BreakContinueStack.pop_back(); - - if (S.getInc()) - EmitBlock(ContinueBlock); - - // If there is an increment, emit it next. - if (S.getInc()) - EmitStmt(S.getInc()); - - // Finally, branch back up to the condition for the next iteration. - Builder.CreateBr(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor); -} - -/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand -/// if the function returns void, or may be missing one if the function returns -/// non-void. Fun stuff :). -void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { - // Emit the result value, even if unused, to evalute the side effects. - const Expr *RV = S.getRetValue(); - - QualType FnRetTy = CurFuncDecl->getType().getCanonicalType(); - FnRetTy = cast(FnRetTy)->getResultType(); - - if (FnRetTy->isVoidType()) { - // If the function returns void, emit ret void. - Builder.CreateRetVoid(); - } else if (RV == 0) { - // Handle "return;" in a function that returns a value. - const llvm::Type *RetTy = CurFn->getFunctionType()->getReturnType(); - if (RetTy == llvm::Type::VoidTy) - Builder.CreateRetVoid(); // struct return etc. - else - Builder.CreateRet(llvm::UndefValue::get(RetTy)); - } else if (!hasAggregateLLVMType(RV->getType())) { - Builder.CreateRet(EmitScalarExpr(RV)); - } else if (RV->getType()->isComplexType()) { - llvm::Value *SRetPtr = CurFn->arg_begin(); - EmitComplexExprIntoAddr(RV, SRetPtr, false); - } else { - llvm::Value *SRetPtr = CurFn->arg_begin(); - EmitAggExpr(RV, SRetPtr, false); - } - - // Emit a block after the branch so that dead code after a return has some - // place to go. - EmitBlock(new llvm::BasicBlock()); -} - -void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) { - for (const ScopedDecl *Decl = S.getDecl(); Decl; - Decl = Decl->getNextDeclarator()) - EmitDecl(*Decl); -} - -void CodeGenFunction::EmitBreakStmt() { - assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!"); - - llvm::BasicBlock *Block = BreakContinueStack.back().BreakBlock; - Builder.CreateBr(Block); - EmitBlock(new llvm::BasicBlock()); -} - -void CodeGenFunction::EmitContinueStmt() { - assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); - - llvm::BasicBlock *Block = BreakContinueStack.back().ContinueBlock; - Builder.CreateBr(Block); - EmitBlock(new llvm::BasicBlock()); -} - -/// EmitCaseStmtRange - If case statement range is not too big then -/// add multiple cases to switch instruction, one for each value within -/// the range. If range is too big then emit "if" condition check. -void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { - assert (S.getRHS() && "Unexpected RHS value in CaseStmt"); - - const Expr *L = S.getLHS(); - const Expr *R = S.getRHS(); - llvm::ConstantInt *LV = cast(EmitScalarExpr(L)); - llvm::ConstantInt *RV = cast(EmitScalarExpr(R)); - llvm::APInt LHS = LV->getValue(); - const llvm::APInt &RHS = RV->getValue(); - - llvm::APInt Range = RHS - LHS; - if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) { - // Range is small enough to add multiple switch instruction cases. - StartBlock("sw.bb"); - llvm::BasicBlock *CaseDest = Builder.GetInsertBlock(); - SwitchInsn->addCase(LV, CaseDest); - LHS++; - while (LHS != RHS) { - SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest); - LHS++; - } - SwitchInsn->addCase(RV, CaseDest); - EmitStmt(S.getSubStmt()); - return; - } - - // The range is too big. Emit "if" condition. - llvm::BasicBlock *FalseDest = NULL; - llvm::BasicBlock *CaseDest = new llvm::BasicBlock("sw.bb"); - - // If we have already seen one case statement range for this switch - // instruction then piggy-back otherwise use default block as false - // destination. - if (CaseRangeBlock) - FalseDest = CaseRangeBlock; - else - FalseDest = SwitchInsn->getDefaultDest(); - - // Start new block to hold case statement range check instructions. - StartBlock("case.range"); - CaseRangeBlock = Builder.GetInsertBlock(); - - // Emit range check. - llvm::Value *Diff = - Builder.CreateSub(SwitchInsn->getCondition(), LV, "tmp"); - llvm::Value *Cond = - Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(Range), "tmp"); - Builder.CreateCondBr(Cond, CaseDest, FalseDest); - - // Now emit case statement body. - EmitBlock(CaseDest); - EmitStmt(S.getSubStmt()); -} - -void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { - if (S.getRHS()) { - EmitCaseStmtRange(S); - return; - } - - StartBlock("sw.bb"); - llvm::BasicBlock *CaseDest = Builder.GetInsertBlock(); - llvm::APSInt CaseVal(32); - S.getLHS()->isIntegerConstantExpr(CaseVal, getContext()); - llvm::ConstantInt *LV = llvm::ConstantInt::get(CaseVal); - SwitchInsn->addCase(LV, CaseDest); - EmitStmt(S.getSubStmt()); -} - -void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) { - StartBlock("sw.default"); - // Current insert block is the default destination. - SwitchInsn->setSuccessor(0, Builder.GetInsertBlock()); - EmitStmt(S.getSubStmt()); -} - -void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { - llvm::Value *CondV = EmitScalarExpr(S.getCond()); - - // Handle nested switch statements. - llvm::SwitchInst *SavedSwitchInsn = SwitchInsn; - llvm::BasicBlock *SavedCRBlock = CaseRangeBlock; - CaseRangeBlock = NULL; - - // Create basic block to hold stuff that comes after switch statement. - // Initially use it to hold DefaultStmt. - llvm::BasicBlock *NextBlock = new llvm::BasicBlock("after.sw"); - SwitchInsn = Builder.CreateSwitch(CondV, NextBlock); - - // All break statements jump to NextBlock. If BreakContinueStack is non empty - // then reuse last ContinueBlock. - llvm::BasicBlock *ContinueBlock = NULL; - if (!BreakContinueStack.empty()) - ContinueBlock = BreakContinueStack.back().ContinueBlock; - BreakContinueStack.push_back(BreakContinue(NextBlock, ContinueBlock)); - - // Emit switch body. - EmitStmt(S.getBody()); - BreakContinueStack.pop_back(); - - // If one or more case statement range is seen then use CaseRangeBlock - // as the default block. False edge of CaseRangeBlock will lead to - // original default block. - if (CaseRangeBlock) - SwitchInsn->setSuccessor(0, CaseRangeBlock); - - // Prune insert block if it is dummy. - llvm::BasicBlock *BB = Builder.GetInsertBlock(); - if (isDummyBlock(BB)) - BB->eraseFromParent(); - else // Otherwise, branch to continuation. - Builder.CreateBr(NextBlock); - - // Place NextBlock as the new insert point. - CurFn->getBasicBlockList().push_back(NextBlock); - Builder.SetInsertPoint(NextBlock); - SwitchInsn = SavedSwitchInsn; - CaseRangeBlock = SavedCRBlock; -} - -static inline std::string ConvertAsmString(const char *Start, - unsigned NumOperands, - bool IsSimple) -{ - static unsigned AsmCounter = 0; - - AsmCounter++; - - std::string Result; - if (IsSimple) { - while (*Start) { - switch (*Start) { - default: - Result += *Start; - break; - case '$': - Result += "$$"; - break; - } - - Start++; - } - - return Result; - } - - while (*Start) { - switch (*Start) { - default: - Result += *Start; - break; - case '$': - Result += "$$"; - break; - case '%': - // Escaped character - Start++; - if (!*Start) { - // FIXME: This should be caught during Sema. - assert(0 && "Trailing '%' in asm string."); - } - - char EscapedChar = *Start; - if (EscapedChar == '%') { - // Escaped percentage sign. - Result += '%'; - } - else if (EscapedChar == '=') { - // Generate an unique ID. - Result += llvm::utostr(AsmCounter); - } else if (isdigit(EscapedChar)) { - // %n - Assembler operand n - char *End; - - unsigned long n = strtoul(Start, &End, 10); - if (Start == End) { - // FIXME: This should be caught during Sema. - assert(0 && "Missing operand!"); - } else if (n >= NumOperands) { - // FIXME: This should be caught during Sema. - assert(0 && "Operand number out of range!"); - } - - Result += '$' + llvm::utostr(n); - Start = End - 1; - } else if (isalpha(EscapedChar)) { - char *End; - - unsigned long n = strtoul(Start + 1, &End, 10); - if (Start == End) { - // FIXME: This should be caught during Sema. - assert(0 && "Missing operand!"); - } else if (n >= NumOperands) { - // FIXME: This should be caught during Sema. - assert(0 && "Operand number out of range!"); - } - - Result += "${" + llvm::utostr(n) + ':' + EscapedChar + '}'; - Start = End - 1; - } else { - assert(0 && "Unhandled asm escaped character!"); - } - } - Start++; - } - - return Result; -} - -static std::string SimplifyConstraint(const char* Constraint, - TargetInfo &Target) { - std::string Result; - - while (*Constraint) { - switch (*Constraint) { - default: - Result += Target.convertConstraint(*Constraint); - break; - // Ignore these - case '*': - case '?': - case '!': - break; - case 'g': - Result += "imr"; - break; - } - - Constraint++; - } - - return Result; -} - -void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { - std::string AsmString = - ConvertAsmString(std::string(S.getAsmString()->getStrData(), - S.getAsmString()->getByteLength()).c_str(), - S.getNumOutputs() + S.getNumInputs(), S.isSimple()); - - std::string Constraints; - - llvm::Value *ResultAddr = 0; - const llvm::Type *ResultType = llvm::Type::VoidTy; - - std::vector ArgTypes; - std::vector Args; - - // Keep track of inout constraints. - std::string InOutConstraints; - std::vector InOutArgs; - std::vector InOutArgTypes; - - for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { - std::string OutputConstraint(S.getOutputConstraint(i)->getStrData(), - S.getOutputConstraint(i)->getByteLength()); - - TargetInfo::ConstraintInfo Info; - bool result = Target.validateOutputConstraint(OutputConstraint.c_str(), - Info); - assert(result && "Failed to parse output constraint"); - - // Simplify the output constraint. - OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target); - - LValue Dest = EmitLValue(S.getOutputExpr(i)); - const llvm::Type *DestValueType = - cast(Dest.getAddress()->getType())->getElementType(); - - // If the first output operand is not a memory dest, we'll - // make it the return value. - if (i == 0 && !(Info & TargetInfo::CI_AllowsMemory) && - DestValueType->isFirstClassType()) { - ResultAddr = Dest.getAddress(); - ResultType = DestValueType; - Constraints += "=" + OutputConstraint; - } else { - ArgTypes.push_back(Dest.getAddress()->getType()); - Args.push_back(Dest.getAddress()); - if (i != 0) - Constraints += ','; - Constraints += "=*"; - Constraints += OutputConstraint; - } - - if (Info & TargetInfo::CI_ReadWrite) { - // FIXME: This code should be shared with the code that handles inputs. - InOutConstraints += ','; - - const Expr *InputExpr = S.getOutputExpr(i); - llvm::Value *Arg; - if ((Info & TargetInfo::CI_AllowsRegister) || - !(Info & TargetInfo::CI_AllowsMemory)) { - if (ConvertType(InputExpr->getType())->isFirstClassType()) { - Arg = EmitScalarExpr(InputExpr); - } else { - assert(0 && "FIXME: Implement passing non first class types as inputs"); - } - } else { - LValue Dest = EmitLValue(InputExpr); - Arg = Dest.getAddress(); - InOutConstraints += '*'; - } - - InOutArgTypes.push_back(Arg->getType()); - InOutArgs.push_back(Arg); - InOutConstraints += OutputConstraint; - } - } - - unsigned NumConstraints = S.getNumOutputs() + S.getNumInputs(); - - for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { - const Expr *InputExpr = S.getInputExpr(i); - - std::string InputConstraint(S.getInputConstraint(i)->getStrData(), - S.getInputConstraint(i)->getByteLength()); - - TargetInfo::ConstraintInfo Info; - bool result = Target.validateInputConstraint(InputConstraint.c_str(), - NumConstraints, - Info); - assert(result && "Failed to parse input constraint"); - - if (i != 0 || S.getNumOutputs() > 0) - Constraints += ','; - - // Simplify the input constraint. - InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target); - - llvm::Value *Arg; - - if ((Info & TargetInfo::CI_AllowsRegister) || - !(Info & TargetInfo::CI_AllowsMemory)) { - if (ConvertType(InputExpr->getType())->isFirstClassType()) { - Arg = EmitScalarExpr(InputExpr); - } else { - assert(0 && "FIXME: Implement passing non first class types as inputs"); - } - } else { - LValue Dest = EmitLValue(InputExpr); - Arg = Dest.getAddress(); - Constraints += '*'; - } - - ArgTypes.push_back(Arg->getType()); - Args.push_back(Arg); - Constraints += InputConstraint; - } - - // Append the "input" part of inout constraints last. - for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { - ArgTypes.push_back(InOutArgTypes[i]); - Args.push_back(InOutArgs[i]); - } - Constraints += InOutConstraints; - - // Clobbers - for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { - std::string Clobber(S.getClobber(i)->getStrData(), - S.getClobber(i)->getByteLength()); - - Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str()); - - if (i != 0 || NumConstraints != 0) - Constraints += ','; - - Constraints += "~{"; - Constraints += Clobber; - Constraints += '}'; - } - - // Add machine specific clobbers - if (const char *C = Target.getClobbers()) { - if (!Constraints.empty()) - Constraints += ','; - Constraints += C; - } - - const llvm::FunctionType *FTy = - llvm::FunctionType::get(ResultType, ArgTypes, false); - - llvm::InlineAsm *IA = - llvm::InlineAsm::get(FTy, AsmString, Constraints, - S.isVolatile() || S.getNumOutputs() == 0); - llvm::Value *Result = Builder.CreateCall(IA, Args.begin(), Args.end(), ""); - if (ResultAddr) - Builder.CreateStore(Result, ResultAddr); -} diff --git a/clang/CodeGen/CodeGenFunction.cpp b/clang/CodeGen/CodeGenFunction.cpp deleted file mode 100644 index 49f23f27c34..00000000000 --- a/clang/CodeGen/CodeGenFunction.cpp +++ /dev/null @@ -1,182 +0,0 @@ -//===--- CodeGenFunction.cpp - Emit LLVM Code from ASTs for a Function ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This coordinates the per-function state used while generating code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "CodeGenModule.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/AST/AST.h" -#include "llvm/CallingConv.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Support/CFG.h" -using namespace clang; -using namespace CodeGen; - -CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) - : CGM(cgm), Target(CGM.getContext().Target), SwitchInsn(NULL), - CaseRangeBlock(NULL) {} - -ASTContext &CodeGenFunction::getContext() const { - return CGM.getContext(); -} - - -llvm::BasicBlock *CodeGenFunction::getBasicBlockForLabel(const LabelStmt *S) { - llvm::BasicBlock *&BB = LabelMap[S]; - if (BB) return BB; - - // Create, but don't insert, the new block. - return BB = new llvm::BasicBlock(S->getName()); -} - -llvm::Constant * -CodeGenFunction::GetAddrOfStaticLocalVar(const BlockVarDecl *BVD) { - return cast(LocalDeclMap[BVD]); -} - -const llvm::Type *CodeGenFunction::ConvertType(QualType T) { - return CGM.getTypes().ConvertType(T); -} - -bool CodeGenFunction::hasAggregateLLVMType(QualType T) { - return !T->isRealType() && !T->isPointerType() && !T->isReferenceType() && - !T->isVoidType() && !T->isVectorType() && !T->isFunctionType(); -} - - -void CodeGenFunction::GenerateCode(const FunctionDecl *FD) { - LLVMIntTy = ConvertType(getContext().IntTy); - LLVMPointerWidth = static_cast( - getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy))); - - CurFuncDecl = FD; - CurFn = cast(CGM.GetAddrOfFunctionDecl(FD, true)); - assert(CurFn->isDeclaration() && "Function already has body?"); - - // TODO: Set up linkage and many other things. Note, this is a simple - // approximation of what we really want. - if (FD->getAttr()) - CurFn->setLinkage(llvm::Function::DLLImportLinkage); - else if (FD->getAttr()) - CurFn->setLinkage(llvm::Function::DLLExportLinkage); - else if (FD->getAttr() || FD->isInline()) - CurFn->setLinkage(llvm::Function::WeakLinkage); - else if (FD->getStorageClass() == FunctionDecl::Static) - CurFn->setLinkage(llvm::Function::InternalLinkage); - - if (FD->getAttr()) - CurFn->setCallingConv(llvm::CallingConv::Fast); - - if (const VisibilityAttr *attr = FD->getAttr()) - CurFn->setVisibility(attr->getVisibility()); - // FIXME: else handle -fvisibility - - - unsigned FuncAttrs = 0; - if (FD->getAttr()) - FuncAttrs |= llvm::ParamAttr::NoUnwind; - if (FD->getAttr()) - FuncAttrs |= llvm::ParamAttr::NoReturn; - - if (FuncAttrs) { - llvm::ParamAttrsWithIndex PAWI = - llvm::ParamAttrsWithIndex::get(0, FuncAttrs); - CurFn->setParamAttrs(llvm::PAListPtr::get(&PAWI, 1)); - } - - llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", CurFn); - - // Create a marker to make it easy to insert allocas into the entryblock - // later. Don't create this with the builder, because we don't want it - // folded. - llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty); - AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "allocapt", - EntryBB); - - Builder.SetInsertPoint(EntryBB); - - // Emit allocs for param decls. Give the LLVM Argument nodes names. - llvm::Function::arg_iterator AI = CurFn->arg_begin(); - - // Name the struct return argument. - if (hasAggregateLLVMType(FD->getResultType())) { - AI->setName("agg.result"); - ++AI; - } - - for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i, ++AI) { - assert(AI != CurFn->arg_end() && "Argument mismatch!"); - EmitParmDecl(*FD->getParamDecl(i), AI); - } - - // Emit the function body. - EmitStmt(FD->getBody()); - - // Emit a return for code that falls off the end. If insert point - // is a dummy block with no predecessors then remove the block itself. - llvm::BasicBlock *BB = Builder.GetInsertBlock(); - if (isDummyBlock(BB)) - BB->eraseFromParent(); - else { - // FIXME: if this is C++ main, this should return 0. - if (CurFn->getReturnType() == llvm::Type::VoidTy) - Builder.CreateRetVoid(); - else - Builder.CreateRet(llvm::UndefValue::get(CurFn->getReturnType())); - } - assert(BreakContinueStack.empty() && - "mismatched push/pop in break/continue stack!"); - - // Remove the AllocaInsertPt instruction, which is just a convenience for us. - AllocaInsertPt->eraseFromParent(); - AllocaInsertPt = 0; - - // Verify that the function is well formed. - assert(!verifyFunction(*CurFn)); -} - -/// isDummyBlock - Return true if BB is an empty basic block -/// with no predecessors. -bool CodeGenFunction::isDummyBlock(const llvm::BasicBlock *BB) { - if (BB->empty() && pred_begin(BB) == pred_end(BB)) - return true; - return false; -} - -/// StartBlock - Start new block named N. If insert block is a dummy block -/// then reuse it. -void CodeGenFunction::StartBlock(const char *N) { - llvm::BasicBlock *BB = Builder.GetInsertBlock(); - if (!isDummyBlock(BB)) - EmitBlock(new llvm::BasicBlock(N)); - else - BB->setName(N); -} - -/// getCGRecordLayout - Return record layout info. -const CGRecordLayout *CodeGenFunction::getCGRecordLayout(CodeGenTypes &CGT, - QualType Ty) { - const RecordType *RTy = Ty->getAsRecordType(); - assert (RTy && "Unexpected type. RecordType expected here."); - - return CGT.getCGRecordLayout(RTy->getDecl()); -} - -/// WarnUnsupported - Print out a warning that codegen doesn't support the -/// specified stmt yet. -void CodeGenFunction::WarnUnsupported(const Stmt *S, const char *Type) { - CGM.WarnUnsupported(S, Type); -} - diff --git a/clang/CodeGen/CodeGenFunction.h b/clang/CodeGen/CodeGenFunction.h deleted file mode 100644 index 509e8296d20..00000000000 --- a/clang/CodeGen/CodeGenFunction.h +++ /dev/null @@ -1,486 +0,0 @@ -//===--- CodeGenFunction.h - Per-Function state for LLVM CodeGen ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the internal per-function state used for llvm translation. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H -#define CLANG_CODEGEN_CODEGENFUNCTION_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/LLVMBuilder.h" -#include - -namespace llvm { - class Module; -} - -namespace clang { - class ASTContext; - class Decl; - class FunctionDecl; - class TargetInfo; - class QualType; - class FunctionTypeProto; - - class Stmt; - class CompoundStmt; - class LabelStmt; - class GotoStmt; - class IfStmt; - class WhileStmt; - class DoStmt; - class ForStmt; - class ReturnStmt; - class DeclStmt; - class CaseStmt; - class DefaultStmt; - class SwitchStmt; - class AsmStmt; - - class Expr; - class DeclRefExpr; - class StringLiteral; - class IntegerLiteral; - class FloatingLiteral; - class CharacterLiteral; - class TypesCompatibleExpr; - - class ImplicitCastExpr; - class CastExpr; - class CallExpr; - class UnaryOperator; - class BinaryOperator; - class CompoundAssignOperator; - class ArraySubscriptExpr; - class OCUVectorElementExpr; - class ConditionalOperator; - class ChooseExpr; - class PreDefinedExpr; - class ObjCStringLiteral; - class MemberExpr; - - class BlockVarDecl; - class EnumConstantDecl; - class ParmVarDecl; - class FieldDecl; -namespace CodeGen { - class CodeGenModule; - class CodeGenTypes; - class CGRecordLayout; - -/// RValue - This trivial value class is used to represent the result of an -/// expression that is evaluated. It can be one of three things: either a -/// 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; - - // FIXME: Aggregate rvalues need to retain information about whether they are - // volatile or not. -public: - - bool isScalar() const { return Flavor == Scalar; } - bool isComplex() const { return Flavor == Complex; } - bool isAggregate() const { return Flavor == Aggregate; } - - /// getScalar() - Return the Value* of this scalar value. - llvm::Value *getScalarVal() const { - assert(isScalar() && "Not a scalar!"); - return V1; - } - - /// getComplexVal - Return the real/imag components of this complex value. - /// - std::pair getComplexVal() const { - return std::pair(V1, V2); - } - - /// getAggregateAddr() - Return the Value* of the address of the aggregate. - llvm::Value *getAggregateAddr() const { - assert(isAggregate() && "Not an aggregate!"); - return V1; - } - - static RValue get(llvm::Value *V) { - RValue ER; - ER.V1 = V; - ER.Flavor = Scalar; - return ER; - } - static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { - RValue ER; - ER.V1 = V1; - ER.V2 = V2; - ER.Flavor = Complex; - return ER; - } - static RValue getComplex(const std::pair &C) { - RValue ER; - ER.V1 = C.first; - ER.V2 = C.second; - ER.Flavor = Complex; - return ER; - } - static RValue getAggregate(llvm::Value *V) { - RValue ER; - ER.V1 = V; - ER.Flavor = Aggregate; - return ER; - } -}; - - -/// LValue - This represents an lvalue references. Because C/C++ allow -/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a -/// bitrange. -class LValue { - // FIXME: Volatility. Restrict? - // alignment? - - enum { - Simple, // This is a normal l-value, use getAddress(). - VectorElt, // This is a vector element l-value (V[i]), use getVector* - BitField, // This is a bitfield l-value, use getBitfield*. - OCUVectorElt // This is an ocu vector subset, use getOCUVectorComp - } LVType; - - llvm::Value *V; - - union { - llvm::Value *VectorIdx; // Index into a vector subscript: V[i] - unsigned VectorElts; // Encoded OCUVector element subset: V.xyx - struct { - unsigned short StartBit; - unsigned short Size; - bool IsSigned; - } BitfieldData; // BitField start bit and size - }; -public: - bool isSimple() const { return LVType == Simple; } - bool isVectorElt() const { return LVType == VectorElt; } - bool isBitfield() const { return LVType == BitField; } - bool isOCUVectorElt() const { return LVType == OCUVectorElt; } - - // simple lvalue - llvm::Value *getAddress() const { assert(isSimple()); return V; } - // vector elt lvalue - llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; } - llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; } - // ocu vector elements. - llvm::Value *getOCUVectorAddr() const { assert(isOCUVectorElt()); return V; } - unsigned getOCUVectorElts() const { - assert(isOCUVectorElt()); - return VectorElts; - } - // bitfield lvalue - llvm::Value *getBitfieldAddr() const { assert(isBitfield()); return V; } - unsigned short getBitfieldStartBit() const { - assert(isBitfield()); - return BitfieldData.StartBit; - } - unsigned short getBitfieldSize() const { - assert(isBitfield()); - return BitfieldData.Size; - } - bool isBitfieldSigned() const { - assert(isBitfield()); - return BitfieldData.IsSigned; - } - - static LValue MakeAddr(llvm::Value *V) { - LValue R; - R.LVType = Simple; - R.V = V; - return R; - } - - static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx) { - LValue R; - R.LVType = VectorElt; - R.V = Vec; - R.VectorIdx = Idx; - return R; - } - - static LValue MakeOCUVectorElt(llvm::Value *Vec, unsigned Elements) { - LValue R; - R.LVType = OCUVectorElt; - R.V = Vec; - R.VectorElts = Elements; - return R; - } - - static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit, - unsigned short Size, bool IsSigned) { - LValue R; - R.LVType = BitField; - R.V = V; - R.BitfieldData.StartBit = StartBit; - R.BitfieldData.Size = Size; - R.BitfieldData.IsSigned = IsSigned; - return R; - } -}; - -/// CodeGenFunction - This class organizes the per-function state that is used -/// while generating LLVM code. -class CodeGenFunction { -public: - CodeGenModule &CGM; // Per-module state. - TargetInfo &Target; - - typedef std::pair ComplexPairTy; - llvm::LLVMFoldingBuilder Builder; - - const FunctionDecl *CurFuncDecl; - llvm::Function *CurFn; - - /// AllocaInsertPoint - This is an instruction in the entry block before which - /// we prefer to insert allocas. - llvm::Instruction *AllocaInsertPt; - - const llvm::Type *LLVMIntTy; - uint32_t LLVMPointerWidth; - -private: - /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C - /// decls. - llvm::DenseMap LocalDeclMap; - - /// LabelMap - This keeps track of the LLVM basic block for each C label. - llvm::DenseMap LabelMap; - - // BreakContinueStack - This keeps track of where break and continue - // statements should jump to. - struct BreakContinue { - BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb) - : BreakBlock(bb), ContinueBlock(cb) {} - - llvm::BasicBlock *BreakBlock; - llvm::BasicBlock *ContinueBlock; - }; - llvm::SmallVector BreakContinueStack; - - /// SwitchInsn - This is nearest current switch instruction. It is null if - /// if current context is not in a switch. - llvm::SwitchInst *SwitchInsn; - - /// CaseRangeBlock - This block holds if condition check for last case - /// statement range in current switch instruction. - llvm::BasicBlock *CaseRangeBlock; - -public: - CodeGenFunction(CodeGenModule &cgm); - - ASTContext &getContext() const; - - void GenerateCode(const FunctionDecl *FD); - - const llvm::Type *ConvertType(QualType T); - - /// hasAggregateLLVMType - Return true if the specified AST type will map into - /// an aggregate LLVM type or is void. - static bool hasAggregateLLVMType(QualType T); - - /// getBasicBlockForLabel - Return the LLVM basicblock that the specified - /// label maps to. - llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S); - - - void EmitBlock(llvm::BasicBlock *BB); - - /// WarnUnsupported - Print out a warning that codegen doesn't support the - /// specified stmt yet. - void WarnUnsupported(const Stmt *S, const char *Type); - - //===--------------------------------------------------------------------===// - // Helpers - //===--------------------------------------------------------------------===// - - /// CreateTempAlloca - This creates a alloca and inserts it into the entry - /// block. - llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, - const char *Name = "tmp"); - - /// EvaluateExprAsBool - Perform the usual unary conversions on the specified - /// expression and compare the result against zero, returning an Int1Ty value. - llvm::Value *EvaluateExprAsBool(const Expr *E); - - /// EmitAnyExpr - Emit code to compute the specified expression which can have - /// any type. The result is returned as an RValue struct. If this is an - /// aggregate expression, the aggloc/agglocvolatile arguments indicate where - /// the result should be returned. - RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0, - bool isAggLocVolatile = false); - - /// isDummyBlock - Return true if BB is an empty basic block - /// with no predecessors. - static bool isDummyBlock(const llvm::BasicBlock *BB); - - /// StartBlock - Start new block named N. If insert block is a dummy block - /// then reuse it. - void StartBlock(const char *N); - - /// getCGRecordLayout - Return record layout info. - const CGRecordLayout *getCGRecordLayout(CodeGenTypes &CGT, QualType RTy); - - /// GetAddrOfStaticLocalVar - Return the address of a static local variable. - llvm::Constant *GetAddrOfStaticLocalVar(const BlockVarDecl *BVD); - //===--------------------------------------------------------------------===// - // Declaration Emission - //===--------------------------------------------------------------------===// - - void EmitDecl(const Decl &D); - void EmitEnumConstantDecl(const EnumConstantDecl &D); - void EmitBlockVarDecl(const BlockVarDecl &D); - void EmitLocalBlockVarDecl(const BlockVarDecl &D); - void EmitStaticBlockVarDecl(const BlockVarDecl &D); - void EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg); - - //===--------------------------------------------------------------------===// - // Statement Emission - //===--------------------------------------------------------------------===// - - void EmitStmt(const Stmt *S); - RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false, - llvm::Value *AggLoc = 0, bool isAggVol = false); - void EmitLabelStmt(const LabelStmt &S); - void EmitGotoStmt(const GotoStmt &S); - void EmitIfStmt(const IfStmt &S); - void EmitWhileStmt(const WhileStmt &S); - void EmitDoStmt(const DoStmt &S); - void EmitForStmt(const ForStmt &S); - void EmitReturnStmt(const ReturnStmt &S); - void EmitDeclStmt(const DeclStmt &S); - void EmitBreakStmt(); - void EmitContinueStmt(); - void EmitSwitchStmt(const SwitchStmt &S); - void EmitDefaultStmt(const DefaultStmt &S); - void EmitCaseStmt(const CaseStmt &S); - void EmitCaseStmtRange(const CaseStmt &S); - void EmitAsmStmt(const AsmStmt &S); - - //===--------------------------------------------------------------------===// - // LValue Expression Emission - //===--------------------------------------------------------------------===// - - /// EmitLValue - Emit code to compute a designator that specifies the location - /// of the expression. - /// - /// This can return one of two things: a simple address or a bitfield - /// reference. In either case, the LLVM Value* in the LValue structure is - /// guaranteed to be an LLVM pointer type. - /// - /// If this returns a bitfield reference, nothing about the pointee type of - /// the LLVM value is known: For example, it may not be a pointer to an - /// integer. - /// - /// If this returns a normal address, and if the lvalue's C type is fixed - /// size, this method guarantees that the returned pointer type will point to - /// an LLVM type of the same size of the lvalue's type. If the lvalue has a - /// variable length type, this is not possible. - /// - LValue EmitLValue(const Expr *E); - - /// EmitLoadOfLValue - Given an expression that represents a value lvalue, - /// this method emits the address of the lvalue, then loads the result as an - /// rvalue, returning the rvalue. - RValue EmitLoadOfLValue(LValue V, QualType LVType); - RValue EmitLoadOfOCUElementLValue(LValue V, QualType LVType); - RValue EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType); - - - /// EmitStoreThroughLValue - Store the specified rvalue into the specified - /// lvalue, where both are guaranteed to the have the same type, and that type - /// is 'Ty'. - void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty); - void EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, QualType Ty); - void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty); - - // Note: only availabe for agg return types - LValue EmitCallExprLValue(const CallExpr *E); - - LValue EmitDeclRefLValue(const DeclRefExpr *E); - LValue EmitStringLiteralLValue(const StringLiteral *E); - LValue EmitPreDefinedLValue(const PreDefinedExpr *E); - LValue EmitUnaryOpLValue(const UnaryOperator *E); - LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); - LValue EmitOCUVectorElementExpr(const OCUVectorElementExpr *E); - LValue EmitMemberExpr(const MemberExpr *E); - - LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field, - bool isUnion); - - //===--------------------------------------------------------------------===// - // Scalar Expression Emission - //===--------------------------------------------------------------------===// - - RValue EmitCallExpr(const CallExpr *E); - RValue EmitCallExpr(Expr *FnExpr, Expr *const *Args, unsigned NumArgs); - RValue EmitCallExpr(llvm::Value *Callee, QualType FnType, - Expr *const *Args, unsigned NumArgs); - RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E); - - llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); - llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); - - llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...); - llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals, - bool isSplat = false); - - llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); - - //===--------------------------------------------------------------------===// - // Expression Emission - //===--------------------------------------------------------------------===// - - // Expressions are broken into three classes: scalar, complex, aggregate. - - /// EmitScalarExpr - Emit the computation of the specified expression of - /// LLVM scalar type, returning the result. - llvm::Value *EmitScalarExpr(const Expr *E); - - /// EmitScalarConversion - Emit a conversion from the specified type to the - /// specified destination type, both of which are LLVM scalar types. - llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy, - QualType DstTy); - - /// EmitComplexToScalarConversion - Emit a conversion from the specified - /// complex type to the specified destination type, where the destination - /// type is an LLVM scalar type. - llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy, - QualType DstTy); - - - /// EmitAggExpr - Emit the computation of the specified expression of - /// aggregate type. The result is computed into DestPtr. Note that if - /// DestPtr is null, the value of the aggregate expression is not needed. - void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest); - - /// EmitComplexExpr - Emit the computation of the specified expression of - /// complex type, returning the result. - ComplexPairTy EmitComplexExpr(const Expr *E); - - /// EmitComplexExprIntoAddr - Emit the computation of the specified expression - /// of complex type, storing into the specified Value*. - void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr, - bool DestIsVolatile); - /// LoadComplexFromAddr - Load a complex number from the specified address. - ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile); -}; -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/clang/CodeGen/CodeGenModule.cpp b/clang/CodeGen/CodeGenModule.cpp deleted file mode 100644 index 43f399a61f2..00000000000 --- a/clang/CodeGen/CodeGenModule.cpp +++ /dev/null @@ -1,509 +0,0 @@ -//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This coordinates the per-module state used while generating code. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenModule.h" -#include "CodeGenFunction.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/CallingConv.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Module.h" -#include "llvm/Intrinsics.h" -#include -using namespace clang; -using namespace CodeGen; - - -CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO, - llvm::Module &M, const llvm::TargetData &TD, - Diagnostic &diags) - : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags), - Types(C, M, TD), MemCpyFn(0), MemSetFn(0), CFConstantStringClassRef(0) { - //TODO: Make this selectable at runtime - Runtime = CreateObjCRuntime(M); -} - -CodeGenModule::~CodeGenModule() { - EmitGlobalCtors(); - delete Runtime; -} - -/// WarnUnsupported - Print out a warning that codegen doesn't support the -/// specified stmt yet. -void CodeGenModule::WarnUnsupported(const Stmt *S, const char *Type) { - unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning, - "cannot codegen this %0 yet"); - SourceRange Range = S->getSourceRange(); - std::string Msg = Type; - getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID, - &Msg, 1, &Range, 1); -} - -/// WarnUnsupported - Print out a warning that codegen doesn't support the -/// specified decl yet. -void CodeGenModule::WarnUnsupported(const Decl *D, const char *Type) { - unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning, - "cannot codegen this %0 yet"); - std::string Msg = Type; - getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID, - &Msg, 1); -} - -/// AddGlobalCtor - Add a function to the list that will be called before -/// main() runs. -void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor) { - // TODO: Type coercion of void()* types. - GlobalCtors.push_back(Ctor); -} - -void CodeGenModule::EmitGlobalCtors() { - // Get the type of @llvm.global_ctors - std::vector CtorFields; - CtorFields.push_back(llvm::IntegerType::get(32)); - // Constructor function type - std::vector VoidArgs; - llvm::FunctionType* CtorFuncTy = llvm::FunctionType::get( - llvm::Type::VoidTy, - VoidArgs, - false); - // i32, function type pair - CtorFields.push_back(llvm::PointerType::getUnqual(CtorFuncTy)); - llvm::StructType* CtorStructTy = llvm::StructType::get(CtorFields, false); - // Array of fields - llvm::ArrayType* GlobalCtorsTy = llvm::ArrayType::get(CtorStructTy, - GlobalCtors.size()); - - const std::string GlobalCtorsVar = std::string("llvm.global_ctors"); - // Define the global variable - llvm::GlobalVariable *GlobalCtorsVal = new llvm::GlobalVariable( - GlobalCtorsTy, - false, - llvm::GlobalValue::AppendingLinkage, - (llvm::Constant*)0, - GlobalCtorsVar, - &TheModule); - - // Populate the array - std::vector CtorValues; - llvm::Constant *MagicNumber = llvm::ConstantInt::get(llvm::IntegerType::Int32Ty, - 65535, - false); - for (std::vector::iterator I = GlobalCtors.begin(), - E = GlobalCtors.end(); I != E; ++I) { - std::vector StructValues; - StructValues.push_back(MagicNumber); - StructValues.push_back(*I); - - llvm::Constant* CtorEntry = llvm::ConstantStruct::get(CtorStructTy, StructValues); - CtorValues.push_back(CtorEntry); - } - llvm::Constant* CtorArray = llvm::ConstantArray::get(GlobalCtorsTy, CtorValues); - GlobalCtorsVal->setInitializer(CtorArray); - -} - -/// ReplaceMapValuesWith - This is a really slow and bad function that -/// searches for any entries in GlobalDeclMap that point to OldVal, changing -/// them to point to NewVal. This is badbadbad, FIXME! -void CodeGenModule::ReplaceMapValuesWith(llvm::Constant *OldVal, - llvm::Constant *NewVal) { - for (llvm::DenseMap::iterator - I = GlobalDeclMap.begin(), E = GlobalDeclMap.end(); I != E; ++I) - if (I->second == OldVal) I->second = NewVal; -} - - -llvm::Constant *CodeGenModule::GetAddrOfFunctionDecl(const FunctionDecl *D, - bool isDefinition) { - // See if it is already in the map. If so, just return it. - llvm::Constant *&Entry = GlobalDeclMap[D]; - if (Entry) return Entry; - - const llvm::Type *Ty = getTypes().ConvertType(D->getType()); - - // Check to see if the function already exists. - llvm::Function *F = getModule().getFunction(D->getName()); - const llvm::FunctionType *FTy = cast(Ty); - - // If it doesn't already exist, just create and return an entry. - if (F == 0) { - // FIXME: param attributes for sext/zext etc. - F = new llvm::Function(FTy, llvm::Function::ExternalLinkage, D->getName(), - &getModule()); - - // Set the appropriate calling convention for the Function. - if (D->getAttr()) - F->setCallingConv(llvm::CallingConv::Fast); - return Entry = F; - } - - // If the pointer type matches, just return it. - llvm::Type *PFTy = llvm::PointerType::getUnqual(Ty); - if (PFTy == F->getType()) return Entry = F; - - // If this isn't a definition, just return it casted to the right type. - if (!isDefinition) - return Entry = llvm::ConstantExpr::getBitCast(F, PFTy); - - // Otherwise, we have a definition after a prototype with the wrong type. - // F is the Function* for the one with the wrong type, we must make a new - // Function* and update everything that used F (a declaration) with the new - // Function* (which will be a definition). - // - // This happens if there is a prototype for a function (e.g. "int f()") and - // then a definition of a different type (e.g. "int f(int x)"). Start by - // making a new function of the correct type, RAUW, then steal the name. - llvm::Function *NewFn = new llvm::Function(FTy, - llvm::Function::ExternalLinkage, - "", &getModule()); - NewFn->takeName(F); - - // Replace uses of F with the Function we will endow with a body. - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(NewFn, F->getType()); - F->replaceAllUsesWith(NewPtrForOldDecl); - - // FIXME: Update the globaldeclmap for the previous decl of this name. We - // really want a way to walk all of these, but we don't have it yet. This - // is incredibly slow! - ReplaceMapValuesWith(F, NewPtrForOldDecl); - - // Ok, delete the old function now, which is dead. - assert(F->isDeclaration() && "Shouldn't replace non-declaration"); - F->eraseFromParent(); - - // Return the new function which has the right type. - return Entry = NewFn; -} - -static bool IsZeroElementArray(const llvm::Type *Ty) { - if (const llvm::ArrayType *ATy = dyn_cast(Ty)) - return ATy->getNumElements() == 0; - return false; -} - -llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, - bool isDefinition) { - assert(D->hasGlobalStorage() && "Not a global variable"); - - // See if it is already in the map. - llvm::Constant *&Entry = GlobalDeclMap[D]; - if (Entry) return Entry; - - QualType ASTTy = D->getType(); - const llvm::Type *Ty = getTypes().ConvertTypeForMem(ASTTy); - - // Check to see if the global already exists. - llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName(), true); - - // If it doesn't already exist, just create and return an entry. - if (GV == 0) { - return Entry = new llvm::GlobalVariable(Ty, false, - llvm::GlobalValue::ExternalLinkage, - 0, D->getName(), &getModule(), 0, - ASTTy.getAddressSpace()); - } - - // If the pointer type matches, just return it. - llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); - if (PTy == GV->getType()) return Entry = GV; - - // If this isn't a definition, just return it casted to the right type. - if (!isDefinition) - return Entry = llvm::ConstantExpr::getBitCast(GV, PTy); - - - // Otherwise, we have a definition after a prototype with the wrong type. - // GV is the GlobalVariable* for the one with the wrong type, we must make a - /// new GlobalVariable* and update everything that used GV (a declaration) - // with the new GlobalVariable* (which will be a definition). - // - // This happens if there is a prototype for a global (e.g. "extern int x[];") - // and then a definition of a different type (e.g. "int x[10];"). Start by - // making a new global of the correct type, RAUW, then steal the name. - llvm::GlobalVariable *NewGV = - new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, - 0, D->getName(), &getModule(), 0, - ASTTy.getAddressSpace()); - NewGV->takeName(GV); - - // Replace uses of GV with the globalvalue we will endow with a body. - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(NewGV, GV->getType()); - GV->replaceAllUsesWith(NewPtrForOldDecl); - - // FIXME: Update the globaldeclmap for the previous decl of this name. We - // really want a way to walk all of these, but we don't have it yet. This - // is incredibly slow! - ReplaceMapValuesWith(GV, NewPtrForOldDecl); - - // Verify that GV was a declaration or something like x[] which turns into - // [0 x type]. - assert((GV->isDeclaration() || - IsZeroElementArray(GV->getType()->getElementType())) && - "Shouldn't replace non-declaration"); - - // Ok, delete the old global now, which is dead. - GV->eraseFromParent(); - - // Return the new global which has the right type. - return Entry = NewGV; -} - - -void CodeGenModule::EmitFunction(const FunctionDecl *FD) { - // If this is not a prototype, emit the body. - if (FD->getBody()) - CodeGenFunction(*this).GenerateCode(FD); -} - -llvm::Constant *CodeGenModule::EmitGlobalInit(const Expr *Expr) { - return EmitConstantExpr(Expr); -} - -void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) { - // If this is just a forward declaration of the variable, don't emit it now, - // allow it to be emitted lazily on its first use. - if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0) - return; - - // Get the global, forcing it to be a direct reference. - llvm::GlobalVariable *GV = - cast(GetAddrOfGlobalVar(D, true)); - - // Convert the initializer, or use zero if appropriate. - llvm::Constant *Init = 0; - if (D->getInit() == 0) { - Init = llvm::Constant::getNullValue(GV->getType()->getElementType()); - } else if (D->getType()->isIntegerType()) { - llvm::APSInt Value(static_cast( - getContext().getTypeSize(D->getInit()->getType()))); - if (D->getInit()->isIntegerConstantExpr(Value, Context)) - Init = llvm::ConstantInt::get(Value); - } - - if (!Init) - Init = EmitGlobalInit(D->getInit()); - - assert(GV->getType()->getElementType() == Init->getType() && - "Initializer codegen type mismatch!"); - GV->setInitializer(Init); - - if (const VisibilityAttr *attr = D->getAttr()) - GV->setVisibility(attr->getVisibility()); - // FIXME: else handle -fvisibility - - // Set the llvm linkage type as appropriate. - if (D->getAttr()) - GV->setLinkage(llvm::Function::DLLImportLinkage); - else if (D->getAttr()) - GV->setLinkage(llvm::Function::DLLExportLinkage); - else if (D->getAttr()) { - GV->setLinkage(llvm::GlobalVariable::WeakLinkage); - - } else { - // FIXME: This isn't right. This should handle common linkage and other - // stuff. - switch (D->getStorageClass()) { - case VarDecl::Auto: - case VarDecl::Register: - assert(0 && "Can't have auto or register globals"); - case VarDecl::None: - if (!D->getInit()) - GV->setLinkage(llvm::GlobalVariable::WeakLinkage); - break; - case VarDecl::Extern: - case VarDecl::PrivateExtern: - // todo: common - break; - case VarDecl::Static: - GV->setLinkage(llvm::GlobalVariable::InternalLinkage); - break; - } - } -} - -/// EmitGlobalVarDeclarator - Emit all the global vars attached to the specified -/// declarator chain. -void CodeGenModule::EmitGlobalVarDeclarator(const FileVarDecl *D) { - for (; D; D = cast_or_null(D->getNextDeclarator())) - EmitGlobalVar(D); -} - -void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { - // Make sure that this type is translated. - Types.UpdateCompletedType(TD); -} - - -/// getBuiltinLibFunction -llvm::Function *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) { - if (BuiltinID > BuiltinFunctions.size()) - BuiltinFunctions.resize(BuiltinID); - - // Cache looked up functions. Since builtin id #0 is invalid we don't reserve - // a slot for it. - assert(BuiltinID && "Invalid Builtin ID"); - llvm::Function *&FunctionSlot = BuiltinFunctions[BuiltinID-1]; - if (FunctionSlot) - return FunctionSlot; - - assert(Context.BuiltinInfo.isLibFunction(BuiltinID) && "isn't a lib fn"); - - // Get the name, skip over the __builtin_ prefix. - const char *Name = Context.BuiltinInfo.GetName(BuiltinID)+10; - - // Get the type for the builtin. - QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context); - const llvm::FunctionType *Ty = - cast(getTypes().ConvertType(Type)); - - // FIXME: This has a serious problem with code like this: - // void abs() {} - // ... __builtin_abs(x); - // The two versions of abs will collide. The fix is for the builtin to win, - // and for the existing one to be turned into a constantexpr cast of the - // builtin. In the case where the existing one is a static function, it - // should just be renamed. - if (llvm::Function *Existing = getModule().getFunction(Name)) { - if (Existing->getFunctionType() == Ty && Existing->hasExternalLinkage()) - return FunctionSlot = Existing; - assert(Existing == 0 && "FIXME: Name collision"); - } - - // FIXME: param attributes for sext/zext etc. - return FunctionSlot = new llvm::Function(Ty, llvm::Function::ExternalLinkage, - Name, &getModule()); -} - -llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys, - unsigned NumTys) { - return llvm::Intrinsic::getDeclaration(&getModule(), - (llvm::Intrinsic::ID)IID, Tys, NumTys); -} - -llvm::Function *CodeGenModule::getMemCpyFn() { - if (MemCpyFn) return MemCpyFn; - llvm::Intrinsic::ID IID; - switch (Context.Target.getPointerWidth(0)) { - default: assert(0 && "Unknown ptr width"); - case 32: IID = llvm::Intrinsic::memcpy_i32; break; - case 64: IID = llvm::Intrinsic::memcpy_i64; break; - } - return MemCpyFn = getIntrinsic(IID); -} - -llvm::Function *CodeGenModule::getMemSetFn() { - if (MemSetFn) return MemSetFn; - llvm::Intrinsic::ID IID; - switch (Context.Target.getPointerWidth(0)) { - default: assert(0 && "Unknown ptr width"); - case 32: IID = llvm::Intrinsic::memset_i32; break; - case 64: IID = llvm::Intrinsic::memset_i64; break; - } - return MemSetFn = getIntrinsic(IID); -} - -llvm::Constant *CodeGenModule:: -GetAddrOfConstantCFString(const std::string &str) { - llvm::StringMapEntry &Entry = - CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); - - if (Entry.getValue()) - return Entry.getValue(); - - std::vector Fields; - - if (!CFConstantStringClassRef) { - const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); - Ty = llvm::ArrayType::get(Ty, 0); - - CFConstantStringClassRef = - new llvm::GlobalVariable(Ty, false, - llvm::GlobalVariable::ExternalLinkage, 0, - "__CFConstantStringClassReference", - &getModule()); - } - - // Class pointer. - llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); - llvm::Constant *Zeros[] = { Zero, Zero }; - llvm::Constant *C = - llvm::ConstantExpr::getGetElementPtr(CFConstantStringClassRef, Zeros, 2); - Fields.push_back(C); - - // Flags. - const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); - Fields.push_back(llvm::ConstantInt::get(Ty, 1992)); - - // String pointer. - C = llvm::ConstantArray::get(str); - C = new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, ".str", &getModule()); - - C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2); - Fields.push_back(C); - - // String length. - Ty = getTypes().ConvertType(getContext().LongTy); - Fields.push_back(llvm::ConstantInt::get(Ty, str.length())); - - // The struct. - Ty = getTypes().ConvertType(getContext().getCFConstantStringType()); - C = llvm::ConstantStruct::get(cast(Ty), Fields); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalVariable::InternalLinkage, - C, "", &getModule()); - GV->setSection("__DATA,__cfstring"); - Entry.setValue(GV); - return GV; -} - -/// GenerateWritableString -- Creates storage for a string literal. -static llvm::Constant *GenerateStringLiteral(const std::string &str, - bool constant, - CodeGenModule &CGM) { - // Create Constant for this string literal - llvm::Constant *C=llvm::ConstantArray::get(str); - - // Create a global variable for this string - C = new llvm::GlobalVariable(C->getType(), constant, - llvm::GlobalValue::InternalLinkage, - C, ".str", &CGM.getModule()); - return C; -} - -/// CodeGenModule::GetAddrOfConstantString -- returns a pointer to the character -/// array containing the literal. The result is pointer to array type. -llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str) { - // Don't share any string literals if writable-strings is turned on. - if (Features.WritableStrings) - return GenerateStringLiteral(str, false, *this); - - llvm::StringMapEntry &Entry = - ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); - - if (Entry.getValue()) - return Entry.getValue(); - - // Create a global variable for this. - llvm::Constant *C = GenerateStringLiteral(str, true, *this); - Entry.setValue(C); - return C; -} diff --git a/clang/CodeGen/CodeGenModule.h b/clang/CodeGen/CodeGenModule.h deleted file mode 100644 index cbea09fd3ec..00000000000 --- a/clang/CodeGen/CodeGenModule.h +++ /dev/null @@ -1,129 +0,0 @@ -//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the internal per-translation-unit state used for llvm translation. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CODEGENMODULE_H -#define CLANG_CODEGEN_CODEGENMODULE_H - -#include "CodeGenTypes.h" -#include "CGObjCRuntime.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" - -namespace llvm { - class Module; - class Constant; - class Function; - class GlobalVariable; - class TargetData; -} - -namespace clang { - class ASTContext; - class FunctionDecl; - class Decl; - class Expr; - class Stmt; - class ValueDecl; - class VarDecl; - class TypeDecl; - class FileVarDecl; - struct LangOptions; - class Diagnostic; - -namespace CodeGen { - - class CodeGenFunction; - -/// CodeGenModule - This class organizes the cross-module state that is used -/// while generating LLVM code. -class CodeGenModule { - ASTContext &Context; - const LangOptions &Features; - llvm::Module &TheModule; - const llvm::TargetData &TheTargetData; - Diagnostic &Diags; - CodeGenTypes Types; - CGObjCRuntime *Runtime; - - llvm::Function *MemCpyFn; - llvm::Function *MemSetFn; - llvm::DenseMap GlobalDeclMap; - std::vector GlobalCtors; - - llvm::StringMap CFConstantStringMap; - llvm::StringMap ConstantStringMap; - llvm::Constant *CFConstantStringClassRef; - - std::vector BuiltinFunctions; -public: - CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M, - const llvm::TargetData &TD, Diagnostic &Diags); - ~CodeGenModule(); - - CGObjCRuntime *getObjCRuntime() { return Runtime; } - ASTContext &getContext() const { return Context; } - const LangOptions &getLangOptions() const { return Features; } - llvm::Module &getModule() const { return TheModule; } - CodeGenTypes &getTypes() { return Types; } - Diagnostic &getDiags() const { return Diags; } - const llvm::TargetData &getTargetData() const { return TheTargetData; } - - llvm::Constant *GetAddrOfFunctionDecl(const FunctionDecl *D, - bool isDefinition); - llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, bool isDefinition); - - - /// getBuiltinLibFunction - Given a builtin id for a function like - /// "__builtin_fabsf", return a Function* for "fabsf". - /// - llvm::Function *getBuiltinLibFunction(unsigned BuiltinID); - llvm::Constant *GetAddrOfConstantCFString(const std::string& str); - - /// GetAddrOfConstantString -- returns a pointer to the character - /// array containing the literal. The result is pointer to array type. - llvm::Constant *GetAddrOfConstantString(const std::string& str); - llvm::Function *getMemCpyFn(); - llvm::Function *getMemSetFn(); - llvm::Function *getIntrinsic(unsigned IID, const llvm::Type **Tys = 0, - unsigned NumTys = 0); - - void AddGlobalCtor(llvm::Function * Ctor); - void EmitGlobalCtors(void); - - void EmitFunction(const FunctionDecl *FD); - void EmitGlobalVar(const FileVarDecl *D); - void EmitGlobalVarDeclarator(const FileVarDecl *D); - void UpdateCompletedType(const TagDecl *D); - llvm::Constant *EmitGlobalInit(const Expr *E); - llvm::Constant *EmitConstantExpr(const Expr *E, CodeGenFunction *CGF = 0); - - /// WarnUnsupported - Print out a warning that codegen doesn't support the - /// specified stmt yet. - - void WarnUnsupported(const Stmt *S, const char *Type); - - /// WarnUnsupported - Print out a warning that codegen doesn't support the - /// specified decl yet. - void WarnUnsupported(const Decl *D, const char *Type); - -private: - /// ReplaceMapValuesWith - This is a really slow and bad function that - /// searches for any entries in GlobalDeclMap that point to OldVal, changing - /// them to point to NewVal. This is badbadbad, FIXME! - void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal); - -}; -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/clang/CodeGen/CodeGenTypes.cpp b/clang/CodeGen/CodeGenTypes.cpp deleted file mode 100644 index 9a669e87056..00000000000 --- a/clang/CodeGen/CodeGenTypes.cpp +++ /dev/null @@ -1,580 +0,0 @@ -//===--- CodeGenTypes.cpp - Type translation for LLVM CodeGen -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the code that handles AST -> LLVM type lowering. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenTypes.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/AST/AST.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Module.h" -#include "llvm/Target/TargetData.h" - -using namespace clang; -using namespace CodeGen; - -namespace { - /// RecordOrganizer - This helper class, used by CGRecordLayout, layouts - /// structs and unions. It manages transient information used during layout. - /// FIXME : Handle field aligments. Handle packed structs. - class RecordOrganizer { - public: - explicit RecordOrganizer(CodeGenTypes &Types) : - CGT(Types), STy(NULL), llvmFieldNo(0), Cursor(0), - llvmSize(0) {} - - /// addField - Add new field. - void addField(const FieldDecl *FD); - - /// addLLVMField - Add llvm struct field that corresponds to llvm type Ty. - /// Increment field count. - void addLLVMField(const llvm::Type *Ty, bool isPaddingField = false); - - /// addPaddingFields - Current cursor is not suitable place to add next - /// field. Add required padding fields. - void addPaddingFields(unsigned WaterMark); - - /// layoutStructFields - Do the actual work and lay out all fields. Create - /// corresponding llvm struct type. This should be invoked only after - /// all fields are added. - void layoutStructFields(const ASTRecordLayout &RL); - - /// layoutUnionFields - Do the actual work and lay out all fields. Create - /// corresponding llvm struct type. This should be invoked only after - /// all fields are added. - void layoutUnionFields(); - - /// getLLVMType - Return associated llvm struct type. This may be NULL - /// if fields are not laid out. - llvm::Type *getLLVMType() const { - return STy; - } - - /// placeBitField - Find a place for FD, which is a bit-field. - void placeBitField(const FieldDecl *FD); - - llvm::SmallSet &getPaddingFields() { - return PaddingFields; - } - - private: - CodeGenTypes &CGT; - llvm::Type *STy; - unsigned llvmFieldNo; - uint64_t Cursor; - uint64_t llvmSize; - llvm::SmallVector FieldDecls; - std::vector LLVMFields; - llvm::SmallSet PaddingFields; - }; -} - -CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, - const llvm::TargetData &TD) - : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD) { -} - -CodeGenTypes::~CodeGenTypes() { - for(llvm::DenseMap::iterator - I = CGRecordLayouts.begin(), E = CGRecordLayouts.end(); - I != E; ++I) - delete I->second; - CGRecordLayouts.clear(); -} - -/// ConvertType - Convert the specified type to its LLVM form. -const llvm::Type *CodeGenTypes::ConvertType(QualType T) { - // See if type is already cached. - llvm::DenseMap::iterator - I = TypeCache.find(T.getCanonicalType().getTypePtr()); - // If type is found in map and this is not a definition for a opaque - // place holder type then use it. Otherwise, convert type T. - if (I != TypeCache.end()) - return I->second.get(); - - const llvm::Type *ResultType = ConvertNewType(T); - TypeCache.insert(std::make_pair(T.getCanonicalType().getTypePtr(), - llvm::PATypeHolder(ResultType))); - return ResultType; -} - -/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from -/// ConvertType in that it is used to convert to the memory representation for -/// a type. For example, the scalar representation for _Bool is i1, but the -/// memory representation is usually i8 or i32, depending on the target. -const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { - const llvm::Type *R = ConvertType(T); - - // If this is a non-bool type, don't map it. - if (R != llvm::Type::Int1Ty) - return R; - - // Otherwise, return an integer of the target-specified size. - return llvm::IntegerType::get((unsigned)Context.getTypeSize(T)); - -} - -/// UpdateCompletedType - When we find the full definition for a TagDecl, -/// replace the 'opaque' type we previously made for it if applicable. -void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { - llvm::DenseMap::iterator TDTI = - TagDeclTypes.find(TD); - if (TDTI == TagDeclTypes.end()) return; - - // Remember the opaque LLVM type for this tagdecl. - llvm::PATypeHolder OpaqueHolder = TDTI->second; - assert(isa(OpaqueHolder.get()) && - "Updating compilation of an already non-opaque type?"); - - // Remove it from TagDeclTypes so that it will be regenerated. - TagDeclTypes.erase(TDTI); - - // Generate the new type. - const llvm::Type *NT = ConvertTagDeclType(TD); - - // Refine the old opaque type to its new definition. - cast(OpaqueHolder.get())->refineAbstractTypeTo(NT); -} - - - -const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { - const clang::Type &Ty = *T.getCanonicalType(); - - switch (Ty.getTypeClass()) { - case Type::TypeName: // typedef isn't canonical. - case Type::TypeOfExp: // typeof isn't canonical. - case Type::TypeOfTyp: // typeof isn't canonical. - assert(0 && "Non-canonical type, shouldn't happen"); - case Type::Builtin: { - switch (cast(Ty).getKind()) { - case BuiltinType::Void: - // LLVM void type can only be used as the result of a function call. Just - // map to the same as char. - return llvm::IntegerType::get(8); - - case BuiltinType::Bool: - // Note that we always return bool as i1 for use as a scalar type. - return llvm::Type::Int1Ty; - - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::Int: - case BuiltinType::UInt: - case BuiltinType::Long: - case BuiltinType::ULong: - case BuiltinType::LongLong: - case BuiltinType::ULongLong: - return llvm::IntegerType::get( - static_cast(Context.getTypeSize(T))); - - case BuiltinType::Float: return llvm::Type::FloatTy; - case BuiltinType::Double: return llvm::Type::DoubleTy; - case BuiltinType::LongDouble: - // FIXME: mapping long double onto double. - return llvm::Type::DoubleTy; - } - break; - } - case Type::Complex: { - std::vector Elts; - Elts.push_back(ConvertType(cast(Ty).getElementType())); - Elts.push_back(Elts[0]); - return llvm::StructType::get(Elts); - } - case Type::Pointer: { - const PointerType &P = cast(Ty); - QualType ETy = P.getPointeeType(); - return llvm::PointerType::get(ConvertType(ETy), ETy.getAddressSpace()); - } - case Type::Reference: { - const ReferenceType &R = cast(Ty); - return llvm::PointerType::getUnqual(ConvertType(R.getReferenceeType())); - } - - case Type::VariableArray: { - const VariableArrayType &A = cast(Ty); - assert(A.getIndexTypeQualifier() == 0 && - "FIXME: We only handle trivial array types so far!"); - // VLAs resolve to the innermost element type; this matches - // the return of alloca, and there isn't any obviously better choice. - return ConvertType(A.getElementType()); - } - case Type::IncompleteArray: { - const IncompleteArrayType &A = cast(Ty); - assert(A.getIndexTypeQualifier() == 0 && - "FIXME: We only handle trivial array types so far!"); - // int X[] -> [0 x int] - return llvm::ArrayType::get(ConvertType(A.getElementType()), 0); - } - case Type::ConstantArray: { - const ConstantArrayType &A = cast(Ty); - const llvm::Type *EltTy = ConvertType(A.getElementType()); - return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue()); - } - case Type::OCUVector: - case Type::Vector: { - const VectorType &VT = cast(Ty); - return llvm::VectorType::get(ConvertType(VT.getElementType()), - VT.getNumElements()); - } - case Type::FunctionNoProto: - case Type::FunctionProto: { - const FunctionType &FP = cast(Ty); - const llvm::Type *ResultType; - - if (FP.getResultType()->isVoidType()) - ResultType = llvm::Type::VoidTy; // Result of function uses llvm void. - else - ResultType = ConvertType(FP.getResultType()); - - // FIXME: Convert argument types. - bool isVarArg; - std::vector ArgTys; - - // Struct return passes the struct byref. - if (!ResultType->isFirstClassType() && ResultType != llvm::Type::VoidTy) { - ArgTys.push_back(llvm::PointerType::get(ResultType, - FP.getResultType().getAddressSpace())); - ResultType = llvm::Type::VoidTy; - } - - if (const FunctionTypeProto *FTP = dyn_cast(&FP)) { - DecodeArgumentTypes(*FTP, ArgTys); - isVarArg = FTP->isVariadic(); - } else { - isVarArg = true; - } - - return llvm::FunctionType::get(ResultType, ArgTys, isVarArg); - } - - case Type::ASQual: - return ConvertType(QualType(cast(Ty).getBaseType(), 0)); - - case Type::ObjCInterface: - assert(0 && "FIXME: add missing functionality here"); - break; - - case Type::ObjCQualifiedInterface: - assert(0 && "FIXME: add missing functionality here"); - break; - - case Type::ObjCQualifiedId: - assert(0 && "FIXME: add missing functionality here"); - break; - - case Type::Tagged: { - const TagDecl *TD = cast(Ty).getDecl(); - const llvm::Type *Res = ConvertTagDeclType(TD); - - std::string TypeName(TD->getKindName()); - TypeName += '.'; - - // Name the codegen type after the typedef name - // if there is no tag type name available - if (TD->getIdentifier()) - TypeName += TD->getName(); - else if (const TypedefType *TdT = dyn_cast(T)) - TypeName += TdT->getDecl()->getName(); - else - TypeName += "anon"; - - TheModule.addTypeName(TypeName, Res); - return Res; - } - } - - // FIXME: implement. - return llvm::OpaqueType::get(); -} - -void CodeGenTypes::DecodeArgumentTypes(const FunctionTypeProto &FTP, - std::vector &ArgTys) { - for (unsigned i = 0, e = FTP.getNumArgs(); i != e; ++i) { - const llvm::Type *Ty = ConvertType(FTP.getArgType(i)); - if (Ty->isFirstClassType()) - ArgTys.push_back(Ty); - else - // byval arguments are always on the stack, which is addr space #0. - ArgTys.push_back(llvm::PointerType::getUnqual(Ty)); - } -} - -/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or -/// enum. -const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { - llvm::DenseMap::iterator TDTI = - TagDeclTypes.find(TD); - - // If we've already compiled this tag type, use the previous definition. - if (TDTI != TagDeclTypes.end()) - return TDTI->second; - - // If this is still a forward definition, just define an opaque type to use - // for this tagged decl. - if (!TD->isDefinition()) { - llvm::Type *ResultType = llvm::OpaqueType::get(); - TagDeclTypes.insert(std::make_pair(TD, ResultType)); - return ResultType; - } - - // Okay, this is a definition of a type. Compile the implementation now. - - if (TD->getKind() == Decl::Enum) { - // Don't bother storing enums in TagDeclTypes. - return ConvertType(cast(TD)->getIntegerType()); - } - - // This decl could well be recursive. In this case, insert an opaque - // definition of this type, which the recursive uses will get. We will then - // refine this opaque version later. - - // Create new OpaqueType now for later use in case this is a recursive - // type. This will later be refined to the actual type. - llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(); - TagDeclTypes.insert(std::make_pair(TD, ResultHolder)); - - const llvm::Type *ResultType; - const RecordDecl *RD = cast(TD); - if (TD->getKind() == Decl::Struct || TD->getKind() == Decl::Class) { - // Layout fields. - RecordOrganizer RO(*this); - for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i) - RO.addField(RD->getMember(i)); - - RO.layoutStructFields(Context.getASTRecordLayout(RD)); - - // Get llvm::StructType. - CGRecordLayouts[TD] = new CGRecordLayout(RO.getLLVMType(), - RO.getPaddingFields()); - ResultType = RO.getLLVMType(); - - } else if (TD->getKind() == Decl::Union) { - // Just use the largest element of the union, breaking ties with the - // highest aligned member. - if (RD->getNumMembers() != 0) { - RecordOrganizer RO(*this); - for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i) - RO.addField(RD->getMember(i)); - - RO.layoutUnionFields(); - - // Get llvm::StructType. - CGRecordLayouts[TD] = new CGRecordLayout(RO.getLLVMType(), - RO.getPaddingFields()); - ResultType = RO.getLLVMType(); - } else { - ResultType = llvm::StructType::get(std::vector()); - } - } else { - assert(0 && "FIXME: Unknown tag decl kind!"); - } - - // Refine our Opaque type to ResultType. This can invalidate ResultType, so - // make sure to read the result out of the holder. - cast(ResultHolder.get()) - ->refineAbstractTypeTo(ResultType); - - return ResultHolder.get(); -} - -/// getLLVMFieldNo - Return llvm::StructType element number -/// that corresponds to the field FD. -unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) { - llvm::DenseMap::iterator - I = FieldInfo.find(FD); - assert (I != FieldInfo.end() && "Unable to find field info"); - return I->second; -} - -/// addFieldInfo - Assign field number to field FD. -void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No) { - FieldInfo[FD] = No; -} - -/// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field FD. -CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) { - llvm::DenseMap::iterator - I = BitFields.find(FD); - assert (I != BitFields.end() && "Unable to find bitfield info"); - return I->second; -} - -/// addBitFieldInfo - Assign a start bit and a size to field FD. -void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned Begin, - unsigned Size) { - BitFields.insert(std::make_pair(FD, BitFieldInfo(Begin, Size))); -} - -/// getCGRecordLayout - Return record layout info for the given llvm::Type. -const CGRecordLayout * -CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const { - llvm::DenseMap::iterator I - = CGRecordLayouts.find(TD); - assert (I != CGRecordLayouts.end() - && "Unable to find record layout information for type"); - return I->second; -} - -/// addField - Add new field. -void RecordOrganizer::addField(const FieldDecl *FD) { - assert (!STy && "Record fields are already laid out"); - FieldDecls.push_back(FD); -} - -/// layoutStructFields - Do the actual work and lay out all fields. Create -/// corresponding llvm struct type. This should be invoked only after -/// all fields are added. -/// FIXME : At the moment assume -/// - one to one mapping between AST FieldDecls and -/// llvm::StructType elements. -/// - Ignore bit fields -/// - Ignore field aligments -/// - Ignore packed structs -void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { - // FIXME : Use SmallVector - llvmSize = 0; - llvmFieldNo = 0; - Cursor = 0; - LLVMFields.clear(); - - for (llvm::SmallVector::iterator I = FieldDecls.begin(), - E = FieldDecls.end(); I != E; ++I) { - const FieldDecl *FD = *I; - - if (FD->isBitField()) - placeBitField(FD); - else { - const llvm::Type *Ty = CGT.ConvertType(FD->getType()); - addLLVMField(Ty); - CGT.addFieldInfo(FD, llvmFieldNo - 1); - Cursor = llvmSize; - } - } - - unsigned StructAlign = RL.getAlignment(); - if (llvmSize % StructAlign) { - unsigned StructPadding = StructAlign - (llvmSize % StructAlign); - addPaddingFields(llvmSize + StructPadding); - } - - STy = llvm::StructType::get(LLVMFields); -} - -/// addPaddingFields - Current cursor is not suitable place to add next field. -/// Add required padding fields. -void RecordOrganizer::addPaddingFields(unsigned WaterMark) { - assert(WaterMark >= llvmSize && "Invalid padding Field"); - unsigned RequiredBits = WaterMark - llvmSize; - unsigned RequiredBytes = (RequiredBits + 7) / 8; - for (unsigned i = 0; i != RequiredBytes; ++i) - addLLVMField(llvm::Type::Int8Ty, true); -} - -/// addLLVMField - Add llvm struct field that corresponds to llvm type Ty. -/// Increment field count. -void RecordOrganizer::addLLVMField(const llvm::Type *Ty, bool isPaddingField) { - - unsigned AlignmentInBits = CGT.getTargetData().getABITypeAlignment(Ty) * 8; - if (llvmSize % AlignmentInBits) { - // At the moment, insert padding fields even if target specific llvm - // type alignment enforces implict padding fields for FD. Later on, - // optimize llvm fields by removing implicit padding fields and - // combining consequetive padding fields. - unsigned Padding = AlignmentInBits - (llvmSize % AlignmentInBits); - addPaddingFields(llvmSize + Padding); - } - - unsigned TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); - llvmSize += TySize; - if (isPaddingField) - PaddingFields.insert(llvmFieldNo); - LLVMFields.push_back(Ty); - ++llvmFieldNo; -} - -/// layoutUnionFields - Do the actual work and lay out all fields. Create -/// corresponding llvm struct type. This should be invoked only after -/// all fields are added. -void RecordOrganizer::layoutUnionFields() { - - unsigned PrimaryEltNo = 0; - std::pair PrimaryElt = - CGT.getContext().getTypeInfo(FieldDecls[0]->getType()); - CGT.addFieldInfo(FieldDecls[0], 0); - - unsigned Size = FieldDecls.size(); - for(unsigned i = 1; i != Size; ++i) { - const FieldDecl *FD = FieldDecls[i]; - assert (!FD->isBitField() && "Bit fields are not yet supported"); - std::pair EltInfo = - CGT.getContext().getTypeInfo(FD->getType()); - - // Use largest element, breaking ties with the hightest aligned member. - if (EltInfo.first > PrimaryElt.first || - (EltInfo.first == PrimaryElt.first && - EltInfo.second > PrimaryElt.second)) { - PrimaryElt = EltInfo; - PrimaryEltNo = i; - } - - // In union, each field gets first slot. - CGT.addFieldInfo(FD, 0); - } - - std::vector Fields; - const llvm::Type *Ty = CGT.ConvertType(FieldDecls[PrimaryEltNo]->getType()); - Fields.push_back(Ty); - STy = llvm::StructType::get(Fields); -} - -/// placeBitField - Find a place for FD, which is a bit-field. -/// This function searches for the last aligned field. If the bit-field fits in -/// it, it is reused. Otherwise, the bit-field is placed in a new field. -void RecordOrganizer::placeBitField(const FieldDecl *FD) { - - assert (FD->isBitField() && "FD is not a bit-field"); - Expr *BitWidth = FD->getBitWidth(); - llvm::APSInt FieldSize(32); - bool isBitField = - BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext()); - assert (isBitField && "Invalid BitField size expression"); - uint64_t BitFieldSize = FieldSize.getZExtValue(); - - const llvm::Type *Ty = CGT.ConvertType(FD->getType()); - uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); - - unsigned Idx = Cursor / TySize; - unsigned BitsLeft = TySize - (Cursor % TySize); - - if (BitsLeft >= BitFieldSize) { - // The bitfield fits in the last aligned field. - // This is : struct { char a; int CurrentField:10;}; - // where 'CurrentField' shares first field with 'a'. - CGT.addFieldInfo(FD, Idx); - CGT.addBitFieldInfo(FD, TySize - BitsLeft, BitFieldSize); - Cursor += BitFieldSize; - } else { - // Place the bitfield in a new LLVM field. - // This is : struct { char a; short CurrentField:10;}; - // where 'CurrentField' needs a new llvm field. - CGT.addFieldInfo(FD, Idx + 1); - CGT.addBitFieldInfo(FD, 0, BitFieldSize); - Cursor = (Idx + 1) * TySize + BitFieldSize; - } - if (Cursor > llvmSize) - addPaddingFields(Cursor); -} diff --git a/clang/CodeGen/CodeGenTypes.h b/clang/CodeGen/CodeGenTypes.h deleted file mode 100644 index 08a2467106a..00000000000 --- a/clang/CodeGen/CodeGenTypes.h +++ /dev/null @@ -1,165 +0,0 @@ -//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the code that handles AST -> LLVM type lowering. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CODEGENTYPES_H -#define CLANG_CODEGEN_CODEGENTYPES_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" -#include - -namespace llvm { - class Module; - class Type; - class PATypeHolder; - class TargetData; -} - -namespace clang { - class ASTContext; - class TagDecl; - class TargetInfo; - class QualType; - class Type; - class FunctionTypeProto; - class FieldDecl; - class RecordDecl; - -namespace CodeGen { - class CodeGenTypes; - - /// CGRecordLayout - This class handles struct and union layout info while - /// lowering AST types to LLVM types. - class CGRecordLayout { - CGRecordLayout(); // DO NOT IMPLEMENT - public: - CGRecordLayout(llvm::Type *T, llvm::SmallSet &PF) - : STy(T), PaddingFields(PF) { - // FIXME : Collect info about fields that requires adjustments - // (i.e. fields that do not directly map to llvm struct fields.) - } - - /// getLLVMType - Return llvm type associated with this record. - llvm::Type *getLLVMType() const { - return STy; - } - - bool isPaddingField(unsigned No) const { - return PaddingFields.count(No) != 0; - } - - unsigned getNumPaddingFields() { - return PaddingFields.size(); - } - - private: - llvm::Type *STy; - llvm::SmallSet PaddingFields; - }; - -/// CodeGenTypes - This class organizes the cross-module state that is used -/// while lowering AST types to LLVM types. -class CodeGenTypes { - ASTContext &Context; - TargetInfo &Target; - llvm::Module& TheModule; - const llvm::TargetData& TheTargetData; - - llvm::DenseMap TagDeclTypes; - - /// CGRecordLayouts - This maps llvm struct type with corresponding - /// record layout info. - /// FIXME : If CGRecordLayout is less than 16 bytes then use - /// inline it in the map. - llvm::DenseMap CGRecordLayouts; - - /// FieldInfo - This maps struct field with corresponding llvm struct type - /// field no. This info is populated by record organizer. - llvm::DenseMap FieldInfo; - -public: - class BitFieldInfo { - public: - explicit BitFieldInfo(unsigned short B, unsigned short S) - : Begin(B), Size(S) {} - - unsigned short Begin; - unsigned short Size; - }; - -private: - llvm::DenseMap BitFields; - - /// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder) - /// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is - /// used instead of llvm::Type because it allows us to bypass potential - /// dangling type pointers due to type refinement on llvm side. - llvm::DenseMap TypeCache; - - /// ConvertNewType - Convert type T into a llvm::Type. Do not use this - /// method directly because it does not do any type caching. This method - /// is available only for ConvertType(). CovertType() is preferred - /// interface to convert type T into a llvm::Type. - const llvm::Type *ConvertNewType(QualType T); -public: - CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD); - ~CodeGenTypes(); - - const llvm::TargetData &getTargetData() const { return TheTargetData; } - TargetInfo &getTarget() const { return Target; } - ASTContext &getContext() const { return Context; } - - /// ConvertType - Convert type T into a llvm::Type. - const llvm::Type *ConvertType(QualType T); - - /// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from - /// ConvertType in that it is used to convert to the memory representation for - /// a type. For example, the scalar representation for _Bool is i1, but the - /// memory representation is usually i8 or i32, depending on the target. - const llvm::Type *ConvertTypeForMem(QualType T); - - - const CGRecordLayout *getCGRecordLayout(const TagDecl*) const; - - /// getLLVMFieldNo - Return llvm::StructType element number - /// that corresponds to the field FD. - unsigned getLLVMFieldNo(const FieldDecl *FD); - - - /// UpdateCompletedType - When we find the full definition for a TagDecl, - /// replace the 'opaque' type we previously made for it if applicable. - void UpdateCompletedType(const TagDecl *TD); - -public: // These are internal details of CGT that shouldn't be used externally. - void DecodeArgumentTypes(const FunctionTypeProto &FTP, - std::vector &ArgTys); - - /// addFieldInfo - Assign field number to field FD. - void addFieldInfo(const FieldDecl *FD, unsigned No); - - /// addBitFieldInfo - Assign a start bit and a size to field FD. - void addBitFieldInfo(const FieldDecl *FD, unsigned Begin, unsigned Size); - - /// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field - /// FD. - BitFieldInfo getBitFieldInfo(const FieldDecl *FD); - - /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or - /// enum. - const llvm::Type *ConvertTagDeclType(const TagDecl *TD); -}; - -} // end namespace CodeGen -} // end namespace clang - -#endif diff --git a/clang/CodeGen/Makefile b/clang/CodeGen/Makefile deleted file mode 100644 index 87bc646424a..00000000000 --- a/clang/CodeGen/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -##===- clang/CodeGen/Makefile ------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the AST -> LLVM code generation library for the -# C-Language front-end. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangCodeGen -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/CodeGen/ModuleBuilder.cpp b/clang/CodeGen/ModuleBuilder.cpp deleted file mode 100644 index 06467488a5e..00000000000 --- a/clang/CodeGen/ModuleBuilder.cpp +++ /dev/null @@ -1,104 +0,0 @@ -//===--- ModuleBuilder.cpp - Emit LLVM Code from ASTs ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This builds an AST and converts it to LLVM Code. -// -//===----------------------------------------------------------------------===// - -#include "clang/CodeGen/ModuleBuilder.h" -#include "CodeGenModule.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// LLVM Emitter - -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "llvm/Module.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetMachine.h" - -namespace { - class CodeGenerator : public ASTConsumer { - Diagnostic &Diags; - const llvm::TargetData *TD; - ASTContext *Ctx; - const LangOptions &Features; - protected: - llvm::Module *&M; - CodeGen::CodeGenModule *Builder; - public: - CodeGenerator(Diagnostic &diags, const LangOptions &LO, - llvm::Module *&DestModule) - : Diags(diags), Features(LO), M(DestModule) {} - - ~CodeGenerator() { - delete Builder; - } - - virtual void Initialize(ASTContext &Context) { - Ctx = &Context; - - M->setTargetTriple(Ctx->Target.getTargetTriple()); - M->setDataLayout(Ctx->Target.getTargetDescription()); - TD = new llvm::TargetData(Ctx->Target.getTargetDescription()); - Builder = new CodeGen::CodeGenModule(Context, Features, *M, *TD, Diags); - } - - virtual void HandleTopLevelDecl(Decl *D) { - // If an error occurred, stop code generation, but continue parsing and - // semantic analysis (to ensure all warnings and errors are emitted). - if (Diags.hasErrorOccurred()) - return; - - if (FunctionDecl *FD = dyn_cast(D)) { - Builder->EmitFunction(FD); - } else if (FileVarDecl *FVD = dyn_cast(D)) { - Builder->EmitGlobalVarDeclarator(FVD); - } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { - if (LSD->getLanguage() == LinkageSpecDecl::lang_cxx) - Builder->WarnUnsupported(LSD, "linkage spec"); - // FIXME: implement C++ linkage, C linkage works mostly by C - // language reuse already. - } else if (FileScopeAsmDecl *AD = dyn_cast(D)) { - std::string AsmString(AD->getAsmString()->getStrData(), - AD->getAsmString()->getByteLength()); - - const std::string &S = Builder->getModule().getModuleInlineAsm(); - if (S.empty()) - Builder->getModule().setModuleInlineAsm(AsmString); - else - Builder->getModule().setModuleInlineAsm(S + '\n' + AsmString); - } else { - assert(isa(D) && "Unknown top level decl"); - // TODO: handle debug info? - } - } - - /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl - /// (e.g. struct, union, enum, class) is completed. This allows the client to - /// hack on the type, which can occur at any point in the file (because these - /// can be defined in declspecs). - virtual void HandleTagDeclDefinition(TagDecl *D) { - Builder->UpdateCompletedType(D); - } - - }; -} - -ASTConsumer *clang::CreateLLVMCodeGen(Diagnostic &Diags, - const LangOptions &Features, - llvm::Module *&DestModule) { - return new CodeGenerator(Diags, Features, DestModule); -} - diff --git a/clang/Headers/Makefile b/clang/Headers/Makefile deleted file mode 100644 index 67891c5f68c..00000000000 --- a/clang/Headers/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -##===- clang/Headers/Makefile ------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -include $(LEVEL)/Makefile.common - -HeaderDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/Headers - -HEADERS := $(notdir $(wildcard $(PROJ_SRC_DIR)/*.h)) - -OBJHEADERS := $(addprefix $(HeaderDir)/, $(HEADERS)) - - -$(OBJHEADERS): $(HeaderDir)/%.h: $(PROJ_SRC_DIR)/%.h $(HeaderDir)/.dir - $(Verb) cp $< $@ - @echo Copying $(notdir $<) to build dir - -printit: - echo $(OBJHEADERS) - echo $(PROJ_SRC_DIR) - -# Hook into the standard Makefile rules. -all-local:: $(OBJHEADERS) - -PROJ_headers := $(DESTDIR)$(PROJ_prefix)/Headers - -INSTHEADERS := $(addprefix $(PROJ_headers)/, $(HEADERS)) - -$(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h $(PROJ_headers)/.dir - $(Verb) $(DataInstall) $< $(PROJ_headers) - -install-local:: $(INSTHEADERS) - diff --git a/clang/Headers/mmintrin.devel.h b/clang/Headers/mmintrin.devel.h deleted file mode 100644 index 70cded027ec..00000000000 --- a/clang/Headers/mmintrin.devel.h +++ /dev/null @@ -1,377 +0,0 @@ -/*===---- mmintrin.h - MMX intrinsics --------------------------------------=== - * - * Copyright (c) 2008 Anders Carlsson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -#ifndef __MMINTRIN_H -#define __MMINTRIN_H - -#ifndef __MMX__ -#error "MMX instruction set not enabled" -#else - -typedef long long __m64 __attribute__((vector_size(8))); - -typedef int __v2si __attribute__((vector_size(8))); -typedef short __v4hi __attribute__((vector_size(8))); -typedef char __v8qi __attribute__((vector_size(8))); - -inline void __attribute__((__always_inline__)) _mm_empty() -{ - __builtin_ia32_emms(); -} - -inline __m64 __attribute__((__always_inline__)) _mm_cvtsi32_si64(int i) -{ - return (__m64)(__v2si){i, 0}; -} - -inline int __attribute__((__always_inline__)) _mm_cvtsi64_si32(__m64 m) -{ - return ((__v2si)m)[0]; -} - -inline __m64 __attribute__((__always_inline__)) _mm_cvtsi64_m64(long long i) -{ - return (__m64)i; -} - -inline long long __attribute__((__always_inline__)) _mm_cvtm64_si64(__m64 m) -{ - return (long long)m; -} - -inline __m64 __attribute__((__always_inline__)) _mm_packs_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_packsswb((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_packs_pi32(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_packssdw((__v2si)m1, (__v2si)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_packs_pu16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_packuswb((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_unpackhi_pi8(__m64 m1, __m64 m2) -{ - // FIXME: use __builtin_shuffle_vector -} - -inline __m64 __attribute__((__always_inline__)) _mm_unpackhi_pi16(__m64 m1, __m64 m2) -{ - // FIXME: use __builtin_shuffle_vector -} - -inline __m64 __attribute__((__always_inline__)) _mm_unpackhi_pi32(__m64 m1, __m64 m2) -{ - // FIXME: use __builtin_shuffle_vector -} - -inline __m64 __attribute__((__always_inline__)) _mm_unpacklo_pi8(__m64 m1, __m64 m2) -{ - // FIXME: use __builtin_shuffle_vector -} - -inline __m64 __attribute__((__always_inline__)) _mm_unpacklo_pi16(__m64 m1, __m64 m2) -{ - // FIXME: use __builtin_shuffle_vector -} - -inline __m64 __attribute__((__always_inline__)) _mm_unpacklo_pi32(__m64 m1, __m64 m2) -{ - // FIXME: use __builtin_shuffle_vector -} - -inline __m64 __attribute__((__always_inline__)) _mm_add_pi8(__m64 m1, __m64 m2) -{ - return (__m64)((__v8qi)m1 + (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_add_pi16(__m64 m1, __m64 m2) -{ - return (__m64)((__v4hi)m1 + (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_add_pi32(__m64 m1, __m64 m2) -{ - return (__m64)((__v2si)m1 + (__v2si)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_adds_pi8(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_paddsb((__v8qi)m1, (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_adds_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_paddsw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_adds_pu8(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_paddusb((__v8qi)m1, (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_adds_pu16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_paddusw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sub_pi8(__m64 m1, __m64 m2) -{ - return (__m64)((__v8qi)m1 - (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sub_pi16(__m64 m1, __m64 m2) -{ - return (__m64)((__v4hi)m1 - (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sub_pi32(__m64 m1, __m64 m2) -{ - return (__m64)((__v2si)m1 - (__v2si)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_subs_pi8(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_psubsb((__v8qi)m1, (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_subs_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_psubsw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_subs_pu8(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_psubusb((__v8qi)m1, (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_subs_pu16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_psubusw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_madd_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pmaddwd((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_mulhi_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pmulhw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_mullo_pi16(__m64 m1, __m64 m2) -{ - return (__m64)((__v4hi)m1 * (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sll_pi16(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_psllw((__v4hi)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_slli_pi16(__m64 m, int count) -{ - return (__m64)__builtin_ia32_psllwi((__v4hi)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sll_pi32(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_pslld((__v2si)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_slli_pi32(__m64 m, int count) -{ - return (__m64)__builtin_ia32_pslldi((__v2si)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sll_pi64(__m64 m, __m64 count) -{ - return __builtin_ia32_psllq(m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_slli_pi64(__m64 m, int count) -{ - return __builtin_ia32_psllqi(m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sra_pi16(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_psraw((__v4hi)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srai_pi16(__m64 m, int count) -{ - return (__m64)__builtin_ia32_psrawi((__v4hi)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_sra_pi32(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_psrad((__v2si)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srai_pi32(__m64 m, int count) -{ - return (__m64)__builtin_ia32_psradi((__v2si)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srl_pi16(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_psrlw((__v4hi)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srli_pi16(__m64 m, int count) -{ - return (__m64)__builtin_ia32_psrlwi((__v4hi)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srl_pi32(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_psrld((__v2si)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srli_pi32(__m64 m, int count) -{ - return (__m64)__builtin_ia32_psrldi((__v2si)m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srl_pi64(__m64 m, __m64 count) -{ - return (__m64)__builtin_ia32_psrlq(m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_srli_pi64(__m64 m, int count) -{ - return __builtin_ia32_psrlqi(m, count); -} - -inline __m64 __attribute__((__always_inline__)) _mm_and_si64(__m64 m1, __m64 m2) -{ - return m1 & m2; -} - -inline __m64 __attribute__((__always_inline__)) _mm_andnot_si64(__m64 m1, __m64 m2) -{ - return ~m1 & m2; -} - -inline __m64 __attribute__((__always_inline__)) _mm_or_si64(__m64 m1, __m64 m2) -{ - return m1 | m2; -} - -inline __m64 __attribute__((__always_inline__)) _mm_xor_si64(__m64 m1, __m64 m2) -{ - return m1 ^ m2; -} - -inline __m64 __attribute__((__always_inline__)) _mm_cmpeq_pi8(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pcmpeqb((__v8qi)m1, (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_cmpeq_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pcmpeqw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_cmpeq_pi32(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pcmpeqd((__v2si)m1, (__v2si)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_cmpgt_pi8(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pcmpgtb((__v8qi)m1, (__v8qi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_cmpgt_pi16(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pcmpgtw((__v4hi)m1, (__v4hi)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_cmpgt_pi32(__m64 m1, __m64 m2) -{ - return (__m64)__builtin_ia32_pcmpgtd((__v2si)m1, (__v2si)m2); -} - -inline __m64 __attribute__((__always_inline__)) _mm_setzero_si64() -{ - return (__m64){ 0LL }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_set_pi32(int i1, int i0) -{ - return (__m64)(__v2si){ i0, i1 }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_set_pi16(short s3, short s2, short s1, short s0) -{ - return (__m64)(__v4hi){ s0, s1, s2, s3 }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_set_pi8(char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0) -{ - return (__m64)(__v8qi){ b0, b1, b2, b3, b4, b5, b6, b7 }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_set1_pi32(int i) -{ - return (__m64)(__v2si){ i, i }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_set1_pi16(short s) -{ - return (__m64)(__v4hi){ s }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_set1_pi8(char b) -{ - return (__m64)(__v8qi){ b }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_setr_pi32(int i1, int i0) -{ - return (__m64)(__v2si){ i1, i0 }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_setr_pi16(short s3, short s2, short s1, short s0) -{ - return (__m64)(__v4hi){ s3, s2, s1, s0 }; -} - -inline __m64 __attribute__((__always_inline__)) _mm_setr_pi8(char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0) -{ - return (__m64)(__v8qi){ b7, b6, b5, b4, b3, b2, b1, b0 }; -} - -#endif /* __MMX__ */ - -#endif /* __MMINTRIN_H */ - diff --git a/clang/Headers/stdbool.h b/clang/Headers/stdbool.h deleted file mode 100644 index e44a1f9a979..00000000000 --- a/clang/Headers/stdbool.h +++ /dev/null @@ -1,38 +0,0 @@ -/*===---- stdbool.h - Standard header for booleans -------------------------=== - * - * Copyright (c) 2008 Eli Friedman - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -#ifndef __STDBOOL_H -#define __STDBOOL_H - -/* Don't define bool, true, and false in C++ */ -#ifndef __cplusplus -#define bool _Bool -#define true 1 -#define false 0 -#endif - -#define __bool_true_false_are_defined 1 - -#endif /* __STDBOOL_H */ diff --git a/clang/Lex/HeaderMap.cpp b/clang/Lex/HeaderMap.cpp deleted file mode 100644 index 282e742b4c8..00000000000 --- a/clang/Lex/HeaderMap.cpp +++ /dev/null @@ -1,242 +0,0 @@ -//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the HeaderMap interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/HeaderMap.h" -#include "clang/Basic/FileManager.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Data Structures and Manifest Constants -//===----------------------------------------------------------------------===// - -enum { - HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p', - HMAP_HeaderVersion = 1, - - HMAP_EmptyBucketKey = 0 -}; - -namespace clang { -struct HMapBucket { - uint32_t Key; // Offset (into strings) of key. - - uint32_t Prefix; // Offset (into strings) of value prefix. - uint32_t Suffix; // Offset (into strings) of value suffix. -}; - -struct HMapHeader { - uint32_t Magic; // Magic word, also indicates byte order. - uint16_t Version; // Version number -- currently 1. - uint16_t Reserved; // Reserved for future use - zero for now. - uint32_t StringsOffset; // Offset to start of string pool. - uint32_t NumEntries; // Number of entries in the string table. - uint32_t NumBuckets; // Number of buckets (always a power of 2). - uint32_t MaxValueLength; // Length of longest result path (excluding nul). - // An array of 'NumBuckets' HMapBucket objects follows this header. - // Strings follow the buckets, at StringsOffset. -}; -} // end namespace clang. - -/// HashHMapKey - This is the 'well known' hash function required by the file -/// format, used to look up keys in the hash table. The hash table uses simple -/// linear probing based on this function. -static inline unsigned HashHMapKey(const char *S, const char *End) { - unsigned Result = 0; - - for (; S != End; S++) - Result += tolower(*S) * 13; - return Result; -} - - - -//===----------------------------------------------------------------------===// -// Verification and Construction -//===----------------------------------------------------------------------===// - -/// HeaderMap::Create - This attempts to load the specified file as a header -/// map. If it doesn't look like a HeaderMap, it gives up and returns null. -/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason -/// into the string error argument and returns null. -const HeaderMap *HeaderMap::Create(const FileEntry *FE) { - // If the file is too small to be a header map, ignore it. - unsigned FileSize = FE->getSize(); - if (FileSize <= sizeof(HMapHeader)) return 0; - - llvm::OwningPtr FileBuffer( - llvm::MemoryBuffer::getFile(FE->getName(), strlen(FE->getName()), 0, - FE->getSize())); - if (FileBuffer == 0) return 0; // Unreadable file? - const char *FileStart = FileBuffer->getBufferStart(); - - // We know the file is at least as big as the header, check it now. - const HMapHeader *Header = reinterpret_cast(FileStart); - - // Sniff it to see if it's a headermap by checking the magic number and - // version. - bool NeedsByteSwap; - if (Header->Magic == HMAP_HeaderMagicNumber && - Header->Version == HMAP_HeaderVersion) - NeedsByteSwap = false; - else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) && - Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion)) - NeedsByteSwap = true; // Mixed endianness headermap. - else - return 0; // Not a header map. - - if (Header->Reserved != 0) return 0; - - // Okay, everything looks good, create the header map. - return new HeaderMap(FileBuffer.take(), NeedsByteSwap); -} - -HeaderMap::~HeaderMap() { - delete FileBuffer; -} - -//===----------------------------------------------------------------------===// -// Utility Methods -//===----------------------------------------------------------------------===// - - -/// getFileName - Return the filename of the headermap. -const char *HeaderMap::getFileName() const { - return FileBuffer->getBufferIdentifier(); -} - -unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const { - if (!NeedsBSwap) return X; - return llvm::ByteSwap_32(X); -} - -/// getHeader - Return a reference to the file header, in unbyte-swapped form. -/// This method cannot fail. -const HMapHeader &HeaderMap::getHeader() const { - // We know the file is at least as big as the header. Return it. - return *reinterpret_cast(FileBuffer->getBufferStart()); -} - -/// getBucket - Return the specified hash table bucket from the header map, -/// bswap'ing its fields as appropriate. If the bucket number is not valid, -/// this return a bucket with an empty key (0). -HMapBucket HeaderMap::getBucket(unsigned BucketNo) const { - HMapBucket Result; - Result.Key = HMAP_EmptyBucketKey; - - const HMapBucket *BucketArray = - reinterpret_cast(FileBuffer->getBufferStart() + - sizeof(HMapHeader)); - - const HMapBucket *BucketPtr = BucketArray+BucketNo; - if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) - return Result; // Invalid buffer, corrupt hmap. - - // Otherwise, the bucket is valid. Load the values, bswapping as needed. - Result.Key = getEndianAdjustedWord(BucketPtr->Key); - Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix); - Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix); - return Result; -} - -/// getString - Look up the specified string in the string table. If the string -/// index is not valid, it returns an empty string. -const char *HeaderMap::getString(unsigned StrTabIdx) const { - // Add the start of the string table to the idx. - StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset); - - // Check for invalid index. - if (StrTabIdx >= FileBuffer->getBufferSize()) - return 0; - - // Otherwise, we have a valid pointer into the file. Just return it. We know - // that the "string" can not overrun the end of the file, because the buffer - // is nul terminated by virtue of being a MemoryBuffer. - return FileBuffer->getBufferStart()+StrTabIdx; -} - -/// StringsEqualWithoutCase - Compare the specified two strings for case- -/// insensitive equality, returning true if they are equal. Both strings are -/// known to have the same length. -static bool StringsEqualWithoutCase(const char *S1, const char *S2, - unsigned Len) { - for (; Len; ++S1, ++S2, --Len) - if (tolower(*S1) != tolower(*S2)) - return false; - return true; -} - -//===----------------------------------------------------------------------===// -// The Main Drivers -//===----------------------------------------------------------------------===// - -/// dump - Print the contents of this headermap to stderr. -void HeaderMap::dump() const { - const HMapHeader &Hdr = getHeader(); - unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); - - fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n", - getFileName(), NumBuckets, - getEndianAdjustedWord(Hdr.NumEntries)); - - for (unsigned i = 0; i != NumBuckets; ++i) { - HMapBucket B = getBucket(i); - if (B.Key == HMAP_EmptyBucketKey) continue; - - const char *Key = getString(B.Key); - const char *Prefix = getString(B.Prefix); - const char *Suffix = getString(B.Suffix); - fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix); - } -} - -/// LookupFile - Check to see if the specified relative filename is located in -/// this HeaderMap. If so, open it and return its FileEntry. -const FileEntry *HeaderMap::LookupFile(const char *FilenameStart, - const char *FilenameEnd, - FileManager &FM) const { - const HMapHeader &Hdr = getHeader(); - unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); - - // If the number of buckets is not a power of two, the headermap is corrupt. - // Don't probe infinitely. - if (NumBuckets & (NumBuckets-1)) - return 0; - - // Linearly probe the hash table. - for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) { - HMapBucket B = getBucket(Bucket & (NumBuckets-1)); - if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss. - - // See if the key matches. If not, probe on. - const char *Key = getString(B.Key); - unsigned BucketKeyLen = strlen(Key); - if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart)) - continue; - - // See if the actual strings equal. - if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen)) - continue; - - // If so, we have a match in the hash table. Construct the destination - // path. - llvm::SmallString<1024> DestPath; - DestPath += getString(B.Prefix); - DestPath += getString(B.Suffix); - return FM.getFile(DestPath.begin(), DestPath.end()); - } -} diff --git a/clang/Lex/HeaderSearch.cpp b/clang/Lex/HeaderSearch.cpp deleted file mode 100644 index 44ae35c8b7e..00000000000 --- a/clang/Lex/HeaderSearch.cpp +++ /dev/null @@ -1,425 +0,0 @@ -//===--- HeaderSearch.cpp - Resolve Header File Locations ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the DirectoryLookup and HeaderSearch interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/HeaderMap.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/IdentifierTable.h" -#include "llvm/System/Path.h" -#include "llvm/ADT/SmallString.h" -using namespace clang; - -HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) { - SystemDirIdx = 0; - NoCurDirSearch = false; - - NumIncluded = 0; - NumMultiIncludeFileOptzn = 0; - NumFrameworkLookups = NumSubFrameworkLookups = 0; -} - -HeaderSearch::~HeaderSearch() { - // Delete headermaps. - for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) - delete HeaderMaps[i].second; -} - -void HeaderSearch::PrintStats() { - fprintf(stderr, "\n*** HeaderSearch Stats:\n"); - fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size()); - unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0; - for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) { - NumOnceOnlyFiles += FileInfo[i].isImport; - if (MaxNumIncludes < FileInfo[i].NumIncludes) - MaxNumIncludes = FileInfo[i].NumIncludes; - NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1; - } - fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles); - fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles); - fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes); - - fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded); - fprintf(stderr, " %d #includes skipped due to" - " the multi-include optimization.\n", NumMultiIncludeFileOptzn); - - fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups); - fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups); -} - -/// CreateHeaderMap - This method returns a HeaderMap for the specified -/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. -const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { - // We expect the number of headermaps to be small, and almost always empty. - // If it ever grows, use of a linear search should be re-evaluated. - if (!HeaderMaps.empty()) { - for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) - // Pointer equality comparison of FileEntries works because they are - // already uniqued by inode. - if (HeaderMaps[i].first == FE) - return HeaderMaps[i].second; - } - - if (const HeaderMap *HM = HeaderMap::Create(FE)) { - HeaderMaps.push_back(std::make_pair(FE, HM)); - return HM; - } - - return 0; -} - -//===----------------------------------------------------------------------===// -// File lookup within a DirectoryLookup scope -//===----------------------------------------------------------------------===// - -/// getName - Return the directory or filename corresponding to this lookup -/// object. -const char *DirectoryLookup::getName() const { - if (isNormalDir()) - return getDir()->getName(); - if (isFramework()) - return getFrameworkDir()->getName(); - assert(isHeaderMap() && "Unknown DirectoryLookup"); - return getHeaderMap()->getFileName(); -} - - -/// LookupFile - Lookup the specified file in this search path, returning it -/// if it exists or returning null if not. -const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart, - const char *FilenameEnd, - HeaderSearch &HS) const { - llvm::SmallString<1024> TmpDir; - if (isNormalDir()) { - // Concatenate the requested file onto the directory. - // FIXME: Portability. Filename concatenation should be in sys::Path. - TmpDir += getDir()->getName(); - TmpDir.push_back('/'); - TmpDir.append(FilenameStart, FilenameEnd); - return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end()); - } - - if (isFramework()) - return DoFrameworkLookup(FilenameStart, FilenameEnd, HS); - - assert(isHeaderMap() && "Unknown directory lookup"); - return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr()); -} - - -/// DoFrameworkLookup - Do a lookup of the specified file in the current -/// DirectoryLookup, which is a framework directory. -const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart, - const char *FilenameEnd, - HeaderSearch &HS) const { - FileManager &FileMgr = HS.getFileMgr(); - - // Framework names must have a '/' in the filename. - const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/'); - if (SlashPos == FilenameEnd) return 0; - - // Find out if this is the home for the specified framework, by checking - // HeaderSearch. Possible answer are yes/no and unknown. - const DirectoryEntry *&FrameworkDirCache = - HS.LookupFrameworkCache(FilenameStart, SlashPos); - - // If it is known and in some other directory, fail. - if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir()) - return 0; - - // Otherwise, construct the path to this framework dir. - - // FrameworkName = "/System/Library/Frameworks/" - llvm::SmallString<1024> FrameworkName; - FrameworkName += getFrameworkDir()->getName(); - if (FrameworkName.empty() || FrameworkName.back() != '/') - FrameworkName.push_back('/'); - - // FrameworkName = "/System/Library/Frameworks/Cocoa" - FrameworkName.append(FilenameStart, SlashPos); - - // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" - FrameworkName += ".framework/"; - - // If the cache entry is still unresolved, query to see if the cache entry is - // still unresolved. If so, check its existence now. - if (FrameworkDirCache == 0) { - HS.IncrementFrameworkLookupCount(); - - // If the framework dir doesn't exist, we fail. - // FIXME: It's probably more efficient to query this with FileMgr.getDir. - if (!llvm::sys::Path(std::string(FrameworkName.begin(), - FrameworkName.end())).exists()) - return 0; - - // Otherwise, if it does, remember that this is the right direntry for this - // framework. - FrameworkDirCache = getFrameworkDir(); - } - - // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" - unsigned OrigSize = FrameworkName.size(); - - FrameworkName += "Headers/"; - FrameworkName.append(SlashPos+1, FilenameEnd); - if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(), - FrameworkName.end())) { - return FE; - } - - // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" - const char *Private = "Private"; - FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, - Private+strlen(Private)); - return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end()); -} - - -//===----------------------------------------------------------------------===// -// Header File Location. -//===----------------------------------------------------------------------===// - - -/// LookupFile - Given a "foo" or reference, look up the indicated file, -/// return null on failure. isAngled indicates whether the file reference is -/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if -/// non-null, indicates where the #including file is, in case a relative search -/// is needed. -const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, - const char *FilenameEnd, - bool isAngled, - const DirectoryLookup *FromDir, - const DirectoryLookup *&CurDir, - const FileEntry *CurFileEnt) { - // If 'Filename' is absolute, check to see if it exists and no searching. - // FIXME: Portability. This should be a sys::Path interface, this doesn't - // handle things like C:\foo.txt right, nor win32 \\network\device\blah. - if (FilenameStart[0] == '/') { - CurDir = 0; - - // If this was an #include_next "/absolute/file", fail. - if (FromDir) return 0; - - // Otherwise, just return the file. - return FileMgr.getFile(FilenameStart, FilenameEnd); - } - - // Step #0, unless disabled, check to see if the file is in the #includer's - // directory. This has to be based on CurFileEnt, not CurDir, because - // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and - // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h". - // This search is not done for <> headers. - if (CurFileEnt && !isAngled && !NoCurDirSearch) { - llvm::SmallString<1024> TmpDir; - // Concatenate the requested file onto the directory. - // FIXME: Portability. Filename concatenation should be in sys::Path. - TmpDir += CurFileEnt->getDir()->getName(); - TmpDir.push_back('/'); - TmpDir.append(FilenameStart, FilenameEnd); - if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) { - // Leave CurDir unset. - // This file is a system header or C++ unfriendly if the old file is. - // - // Note that the temporary 'DirInfo' is required here, as either call to - // getFileInfo could resize the vector and we don't want to rely on order - // of evaluation. - unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo; - getFileInfo(FE).DirInfo = DirInfo; - return FE; - } - } - - CurDir = 0; - - // If this is a system #include, ignore the user #include locs. - unsigned i = isAngled ? SystemDirIdx : 0; - - // If this is a #include_next request, start searching after the directory the - // file was found in. - if (FromDir) - i = FromDir-&SearchDirs[0]; - - // Cache all of the lookups performed by this method. Many headers are - // multiply included, and the "pragma once" optimization prevents them from - // being relex/pp'd, but they would still have to search through a - // (potentially huge) series of SearchDirs to find it. - std::pair &CacheLookup = - LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue(); - - // If the entry has been previously looked up, the first value will be - // non-zero. If the value is equal to i (the start point of our search), then - // this is a matching hit. - if (CacheLookup.first == i+1) { - // Skip querying potentially lots of directories for this lookup. - i = CacheLookup.second; - } else { - // Otherwise, this is the first query, or the previous query didn't match - // our search start. We will fill in our found location below, so prime the - // start point value. - CacheLookup.first = i+1; - } - - // Check each directory in sequence to see if it contains this file. - for (; i != SearchDirs.size(); ++i) { - const FileEntry *FE = - SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this); - if (!FE) continue; - - CurDir = &SearchDirs[i]; - - // This file is a system header or C++ unfriendly if the dir is. - getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic(); - - // Remember this location for the next lookup we do. - CacheLookup.second = i; - return FE; - } - - // Otherwise, didn't find it. Remember we didn't find this. - CacheLookup.second = SearchDirs.size(); - return 0; -} - -/// LookupSubframeworkHeader - Look up a subframework for the specified -/// #include file. For example, if #include'ing from -/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox -/// is a subframework within Carbon.framework. If so, return the FileEntry -/// for the designated file, otherwise return null. -const FileEntry *HeaderSearch:: -LookupSubframeworkHeader(const char *FilenameStart, - const char *FilenameEnd, - const FileEntry *ContextFileEnt) { - assert(ContextFileEnt && "No context file?"); - - // Framework names must have a '/' in the filename. Find it. - const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/'); - if (SlashPos == FilenameEnd) return 0; - - // Look up the base framework name of the ContextFileEnt. - const char *ContextName = ContextFileEnt->getName(); - - // If the context info wasn't a framework, couldn't be a subframework. - const char *FrameworkPos = strstr(ContextName, ".framework/"); - if (FrameworkPos == 0) - return 0; - - llvm::SmallString<1024> FrameworkName(ContextName, - FrameworkPos+strlen(".framework/")); - - // Append Frameworks/HIToolbox.framework/ - FrameworkName += "Frameworks/"; - FrameworkName.append(FilenameStart, SlashPos); - FrameworkName += ".framework/"; - - llvm::StringMapEntry &CacheLookup = - FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos); - - // Some other location? - if (CacheLookup.getValue() && - CacheLookup.getKeyLength() == FrameworkName.size() && - memcmp(CacheLookup.getKeyData(), &FrameworkName[0], - CacheLookup.getKeyLength()) != 0) - return 0; - - // Cache subframework. - if (CacheLookup.getValue() == 0) { - ++NumSubFrameworkLookups; - - // If the framework dir doesn't exist, we fail. - const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(), - FrameworkName.end()); - if (Dir == 0) return 0; - - // Otherwise, if it does, remember that this is the right direntry for this - // framework. - CacheLookup.setValue(Dir); - } - - const FileEntry *FE = 0; - - // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h" - llvm::SmallString<1024> HeadersFilename(FrameworkName); - HeadersFilename += "Headers/"; - HeadersFilename.append(SlashPos+1, FilenameEnd); - if (!(FE = FileMgr.getFile(HeadersFilename.begin(), - HeadersFilename.end()))) { - - // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h" - HeadersFilename = FrameworkName; - HeadersFilename += "PrivateHeaders/"; - HeadersFilename.append(SlashPos+1, FilenameEnd); - if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end()))) - return 0; - } - - // This file is a system header or C++ unfriendly if the old file is. - // - // Note that the temporary 'DirInfo' is required here, as either call to - // getFileInfo could resize the vector and we don't want to rely on order - // of evaluation. - unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo; - getFileInfo(FE).DirInfo = DirInfo; - return FE; -} - -//===----------------------------------------------------------------------===// -// File Info Management. -//===----------------------------------------------------------------------===// - - -/// getFileInfo - Return the PerFileInfo structure for the specified -/// FileEntry. -HeaderSearch::PerFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { - if (FE->getUID() >= FileInfo.size()) - FileInfo.resize(FE->getUID()+1); - return FileInfo[FE->getUID()]; -} - -/// ShouldEnterIncludeFile - Mark the specified file as a target of of a -/// #include, #include_next, or #import directive. Return false if #including -/// the file will have no effect or true if we should include it. -bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ - ++NumIncluded; // Count # of attempted #includes. - - // Get information about this file. - PerFileInfo &FileInfo = getFileInfo(File); - - // If this is a #import directive, check that we have not already imported - // this header. - if (isImport) { - // If this has already been imported, don't import it again. - FileInfo.isImport = true; - - // Has this already been #import'ed or #include'd? - if (FileInfo.NumIncludes) return false; - } else { - // Otherwise, if this is a #include of a file that was previously #import'd - // or if this is the second #include of a #pragma once file, ignore it. - if (FileInfo.isImport) - return false; - } - - // Next, check to see if the file is wrapped with #ifndef guards. If so, and - // if the macro that guards it is defined, we know the #include has no effect. - if (FileInfo.ControllingMacro && - FileInfo.ControllingMacro->hasMacroDefinition()) { - ++NumMultiIncludeFileOptzn; - return false; - } - - // Increment the number of times this file has been included. - ++FileInfo.NumIncludes; - - return true; -} - - diff --git a/clang/Lex/Lexer.cpp b/clang/Lex/Lexer.cpp deleted file mode 100644 index 98bbb386305..00000000000 --- a/clang/Lex/Lexer.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -//===--- Lexer.cpp - C Language Family Lexer ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Lexer and Token interfaces. -// -//===----------------------------------------------------------------------===// -// -// TODO: GCC Diagnostics emitted by the lexer: -// PEDWARN: (form feed|vertical tab) in preprocessing directive -// -// Universal characters, unicode, char mapping: -// WARNING: `%.*s' is not in NFKC -// WARNING: `%.*s' is not in NFC -// -// Other: -// TODO: Options to support: -// -fexec-charset,-fwide-exec-charset -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Lexer.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/MemoryBuffer.h" -#include -using namespace clang; - -static void InitCharacterInfo(); - -//===----------------------------------------------------------------------===// -// Token Class Implementation -//===----------------------------------------------------------------------===// - -/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. -bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const { - return is(tok::identifier) && - getIdentifierInfo()->getObjCKeywordID() == objcKey; -} - -/// getObjCKeywordID - Return the ObjC keyword kind. -tok::ObjCKeywordKind Token::getObjCKeywordID() const { - IdentifierInfo *specId = getIdentifierInfo(); - return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; -} - -/// isNamedIdentifier - Return true if this token is a ppidentifier with the -/// specified name. For example, tok.isNamedIdentifier("this"). -bool Token::isNamedIdentifier(const char *Name) const { - return IdentInfo && !strcmp(IdentInfo->getName(), Name); -} - - -//===----------------------------------------------------------------------===// -// Lexer Class Implementation -//===----------------------------------------------------------------------===// - - -/// Lexer constructor - Create a new lexer object for the specified buffer -/// with the specified preprocessor managing the lexing process. This lexer -/// assumes that the associated file buffer and Preprocessor objects will -/// outlive it, so it doesn't take ownership of either of them. -Lexer::Lexer(SourceLocation fileloc, Preprocessor &pp, - const char *BufStart, const char *BufEnd) - : FileLoc(fileloc), PP(&pp), Features(pp.getLangOptions()) { - - SourceManager &SourceMgr = PP->getSourceManager(); - unsigned InputFileID = SourceMgr.getPhysicalLoc(FileLoc).getFileID(); - const llvm::MemoryBuffer *InputFile = SourceMgr.getBuffer(InputFileID); - - Is_PragmaLexer = false; - InitCharacterInfo(); - - // BufferStart must always be InputFile->getBufferStart(). - BufferStart = InputFile->getBufferStart(); - - // BufferPtr and BufferEnd can start out somewhere inside the current buffer. - // If unspecified, they starts at the start/end of the buffer. - BufferPtr = BufStart ? BufStart : BufferStart; - BufferEnd = BufEnd ? BufEnd : InputFile->getBufferEnd(); - - assert(BufferEnd[0] == 0 && - "We assume that the input buffer has a null character at the end" - " to simplify lexing!"); - - // Start of the file is a start of line. - IsAtStartOfLine = true; - - // We are not after parsing a #. - ParsingPreprocessorDirective = false; - - // We are not after parsing #include. - ParsingFilename = false; - - // We are not in raw mode. Raw mode disables diagnostics and interpretation - // of tokens (e.g. identifiers, thus disabling macro expansion). It is used - // to quickly lex the tokens of the buffer, e.g. when handling a "#if 0" block - // or otherwise skipping over tokens. - LexingRawMode = false; - - // Default to keeping comments if requested. - KeepCommentMode = PP->getCommentRetentionState(); -} - -/// Lexer constructor - Create a new raw lexer object. This object is only -/// suitable for calls to 'LexRawToken'. This lexer assumes that the -/// associated file buffer will outlive it, so it doesn't take ownership of -/// either of them. -Lexer::Lexer(SourceLocation fileloc, const LangOptions &features, - const char *BufStart, const char *BufEnd) - : FileLoc(fileloc), PP(0), Features(features) { - Is_PragmaLexer = false; - InitCharacterInfo(); - - BufferStart = BufStart; - BufferPtr = BufStart; - BufferEnd = BufEnd; - - assert(BufferEnd[0] == 0 && - "We assume that the input buffer has a null character at the end" - " to simplify lexing!"); - - // Start of the file is a start of line. - IsAtStartOfLine = true; - - // We are not after parsing a #. - ParsingPreprocessorDirective = false; - - // We are not after parsing #include. - ParsingFilename = false; - - // We *are* in raw mode. - LexingRawMode = true; - - // Never keep comments in raw mode. - KeepCommentMode = false; -} - - -/// Stringify - Convert the specified string into a C string, with surrounding -/// ""'s, and with escaped \ and " characters. -std::string Lexer::Stringify(const std::string &Str, bool Charify) { - std::string Result = Str; - char Quote = Charify ? '\'' : '"'; - for (unsigned i = 0, e = Result.size(); i != e; ++i) { - if (Result[i] == '\\' || Result[i] == Quote) { - Result.insert(Result.begin()+i, '\\'); - ++i; ++e; - } - } - return Result; -} - -/// Stringify - Convert the specified string into a C string by escaping '\' -/// and " characters. This does not add surrounding ""'s to the string. -void Lexer::Stringify(llvm::SmallVectorImpl &Str) { - for (unsigned i = 0, e = Str.size(); i != e; ++i) { - if (Str[i] == '\\' || Str[i] == '"') { - Str.insert(Str.begin()+i, '\\'); - ++i; ++e; - } - } -} - - -/// MeasureTokenLength - Relex the token at the specified location and return -/// its length in bytes in the input file. If the token needs cleaning (e.g. -/// includes a trigraph or an escaped newline) then this count includes bytes -/// that are part of that. -unsigned Lexer::MeasureTokenLength(SourceLocation Loc, - const SourceManager &SM) { - // If this comes from a macro expansion, we really do want the macro name, not - // the token this macro expanded to. - Loc = SM.getLogicalLoc(Loc); - - const char *StrData = SM.getCharacterData(Loc); - - // TODO: this could be special cased for common tokens like identifiers, ')', - // etc to make this faster, if it mattered. Just look at StrData[0] to handle - // all obviously single-char tokens. This could use - // Lexer::isObviouslySimpleCharacter for example to handle identifiers or - // something. - - - const char *BufEnd = SM.getBufferData(Loc.getFileID()).second; - - // Create a langops struct and enable trigraphs. This is sufficient for - // measuring tokens. - LangOptions LangOpts; - LangOpts.Trigraphs = true; - - // Create a lexer starting at the beginning of this token. - Lexer TheLexer(Loc, LangOpts, StrData, BufEnd); - Token TheTok; - TheLexer.LexRawToken(TheTok); - return TheTok.getLength(); -} - -//===----------------------------------------------------------------------===// -// Character information. -//===----------------------------------------------------------------------===// - -static unsigned char CharInfo[256]; - -enum { - CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0' - CHAR_VERT_WS = 0x02, // '\r', '\n' - CHAR_LETTER = 0x04, // a-z,A-Z - CHAR_NUMBER = 0x08, // 0-9 - CHAR_UNDER = 0x10, // _ - CHAR_PERIOD = 0x20 // . -}; - -static void InitCharacterInfo() { - static bool isInited = false; - if (isInited) return; - isInited = true; - - // Intiialize the CharInfo table. - // TODO: statically initialize this. - CharInfo[(int)' '] = CharInfo[(int)'\t'] = - CharInfo[(int)'\f'] = CharInfo[(int)'\v'] = CHAR_HORZ_WS; - CharInfo[(int)'\n'] = CharInfo[(int)'\r'] = CHAR_VERT_WS; - - CharInfo[(int)'_'] = CHAR_UNDER; - CharInfo[(int)'.'] = CHAR_PERIOD; - for (unsigned i = 'a'; i <= 'z'; ++i) - CharInfo[i] = CharInfo[i+'A'-'a'] = CHAR_LETTER; - for (unsigned i = '0'; i <= '9'; ++i) - CharInfo[i] = CHAR_NUMBER; -} - -/// isIdentifierBody - Return true if this is the body character of an -/// identifier, which is [a-zA-Z0-9_]. -static inline bool isIdentifierBody(unsigned char c) { - return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER)) ? true : false; -} - -/// isHorizontalWhitespace - Return true if this character is horizontal -/// whitespace: ' ', '\t', '\f', '\v'. Note that this returns false for '\0'. -static inline bool isHorizontalWhitespace(unsigned char c) { - return (CharInfo[c] & CHAR_HORZ_WS) ? true : false; -} - -/// isWhitespace - Return true if this character is horizontal or vertical -/// whitespace: ' ', '\t', '\f', '\v', '\n', '\r'. Note that this returns false -/// for '\0'. -static inline bool isWhitespace(unsigned char c) { - return (CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS)) ? true : false; -} - -/// isNumberBody - Return true if this is the body character of an -/// preprocessing number, which is [a-zA-Z0-9_.]. -static inline bool isNumberBody(unsigned char c) { - return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ? - true : false; -} - - -//===----------------------------------------------------------------------===// -// Diagnostics forwarding code. -//===----------------------------------------------------------------------===// - -/// GetMappedTokenLoc - If lexing out of a 'mapped buffer', where we pretend the -/// lexer buffer was all instantiated at a single point, perform the mapping. -/// This is currently only used for _Pragma implementation, so it is the slow -/// path of the hot getSourceLocation method. Do not allow it to be inlined. -static SourceLocation GetMappedTokenLoc(Preprocessor &PP, - SourceLocation FileLoc, - unsigned CharNo) DISABLE_INLINE; -static SourceLocation GetMappedTokenLoc(Preprocessor &PP, - SourceLocation FileLoc, - unsigned CharNo) { - // Otherwise, we're lexing "mapped tokens". This is used for things like - // _Pragma handling. Combine the instantiation location of FileLoc with the - // physical location. - SourceManager &SourceMgr = PP.getSourceManager(); - - // Create a new SLoc which is expanded from logical(FileLoc) but whose - // characters come from phys(FileLoc)+Offset. - SourceLocation VirtLoc = SourceMgr.getLogicalLoc(FileLoc); - SourceLocation PhysLoc = SourceMgr.getPhysicalLoc(FileLoc); - PhysLoc = SourceLocation::getFileLoc(PhysLoc.getFileID(), CharNo); - return SourceMgr.getInstantiationLoc(PhysLoc, VirtLoc); -} - -/// getSourceLocation - Return a source location identifier for the specified -/// offset in the current file. -SourceLocation Lexer::getSourceLocation(const char *Loc) const { - assert(Loc >= BufferStart && Loc <= BufferEnd && - "Location out of range for this buffer!"); - - // In the normal case, we're just lexing from a simple file buffer, return - // the file id from FileLoc with the offset specified. - unsigned CharNo = Loc-BufferStart; - if (FileLoc.isFileID()) - return SourceLocation::getFileLoc(FileLoc.getFileID(), CharNo); - - assert(PP && "This doesn't work on raw lexers"); - return GetMappedTokenLoc(*PP, FileLoc, CharNo); -} - -/// Diag - Forwarding function for diagnostics. This translate a source -/// position in the current buffer into a SourceLocation object for rendering. -void Lexer::Diag(const char *Loc, unsigned DiagID, - const std::string &Msg) const { - if (LexingRawMode && Diagnostic::isBuiltinNoteWarningOrExtension(DiagID)) - return; - PP->Diag(getSourceLocation(Loc), DiagID, Msg); -} -void Lexer::Diag(SourceLocation Loc, unsigned DiagID, - const std::string &Msg) const { - if (LexingRawMode && Diagnostic::isBuiltinNoteWarningOrExtension(DiagID)) - return; - PP->Diag(Loc, DiagID, Msg); -} - - -//===----------------------------------------------------------------------===// -// Trigraph and Escaped Newline Handling Code. -//===----------------------------------------------------------------------===// - -/// GetTrigraphCharForLetter - Given a character that occurs after a ?? pair, -/// return the decoded trigraph letter it corresponds to, or '\0' if nothing. -static char GetTrigraphCharForLetter(char Letter) { - switch (Letter) { - default: return 0; - case '=': return '#'; - case ')': return ']'; - case '(': return '['; - case '!': return '|'; - case '\'': return '^'; - case '>': return '}'; - case '/': return '\\'; - case '<': return '{'; - case '-': return '~'; - } -} - -/// DecodeTrigraphChar - If the specified character is a legal trigraph when -/// prefixed with ??, emit a trigraph warning. If trigraphs are enabled, -/// return the result character. Finally, emit a warning about trigraph use -/// whether trigraphs are enabled or not. -static char DecodeTrigraphChar(const char *CP, Lexer *L) { - char Res = GetTrigraphCharForLetter(*CP); - if (Res && L) { - if (!L->getFeatures().Trigraphs) { - L->Diag(CP-2, diag::trigraph_ignored); - return 0; - } else { - L->Diag(CP-2, diag::trigraph_converted, std::string()+Res); - } - } - return Res; -} - -/// getCharAndSizeSlow - Peek a single 'character' from the specified buffer, -/// get its size, and return it. This is tricky in several cases: -/// 1. If currently at the start of a trigraph, we warn about the trigraph, -/// then either return the trigraph (skipping 3 chars) or the '?', -/// depending on whether trigraphs are enabled or not. -/// 2. If this is an escaped newline (potentially with whitespace between -/// the backslash and newline), implicitly skip the newline and return -/// the char after it. -/// 3. If this is a UCN, return it. FIXME: C++ UCN's? -/// -/// This handles the slow/uncommon case of the getCharAndSize method. Here we -/// know that we can accumulate into Size, and that we have already incremented -/// Ptr by Size bytes. -/// -/// NOTE: When this method is updated, getCharAndSizeSlowNoWarn (below) should -/// be updated to match. -/// -char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size, - Token *Tok) { - // If we have a slash, look for an escaped newline. - if (Ptr[0] == '\\') { - ++Size; - ++Ptr; -Slash: - // Common case, backslash-char where the char is not whitespace. - if (!isWhitespace(Ptr[0])) return '\\'; - - // See if we have optional whitespace characters followed by a newline. - { - unsigned SizeTmp = 0; - do { - ++SizeTmp; - if (Ptr[SizeTmp-1] == '\n' || Ptr[SizeTmp-1] == '\r') { - // Remember that this token needs to be cleaned. - if (Tok) Tok->setFlag(Token::NeedsCleaning); - - // Warn if there was whitespace between the backslash and newline. - if (SizeTmp != 1 && Tok) - Diag(Ptr, diag::backslash_newline_space); - - // If this is a \r\n or \n\r, skip the newlines. - if ((Ptr[SizeTmp] == '\r' || Ptr[SizeTmp] == '\n') && - Ptr[SizeTmp-1] != Ptr[SizeTmp]) - ++SizeTmp; - - // Found backslash. Parse the char after it. - Size += SizeTmp; - Ptr += SizeTmp; - // Use slow version to accumulate a correct size field. - return getCharAndSizeSlow(Ptr, Size, Tok); - } - } while (isWhitespace(Ptr[SizeTmp])); - } - - // Otherwise, this is not an escaped newline, just return the slash. - return '\\'; - } - - // If this is a trigraph, process it. - if (Ptr[0] == '?' && Ptr[1] == '?') { - // If this is actually a legal trigraph (not something like "??x"), emit - // a trigraph warning. If so, and if trigraphs are enabled, return it. - if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) { - // Remember that this token needs to be cleaned. - if (Tok) Tok->setFlag(Token::NeedsCleaning); - - Ptr += 3; - Size += 3; - if (C == '\\') goto Slash; - return C; - } - } - - // If this is neither, return a single character. - ++Size; - return *Ptr; -} - - -/// getCharAndSizeSlowNoWarn - Handle the slow/uncommon case of the -/// getCharAndSizeNoWarn method. Here we know that we can accumulate into Size, -/// and that we have already incremented Ptr by Size bytes. -/// -/// NOTE: When this method is updated, getCharAndSizeSlow (above) should -/// be updated to match. -char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, - const LangOptions &Features) { - // If we have a slash, look for an escaped newline. - if (Ptr[0] == '\\') { - ++Size; - ++Ptr; -Slash: - // Common case, backslash-char where the char is not whitespace. - if (!isWhitespace(Ptr[0])) return '\\'; - - // See if we have optional whitespace characters followed by a newline. - { - unsigned SizeTmp = 0; - do { - ++SizeTmp; - if (Ptr[SizeTmp-1] == '\n' || Ptr[SizeTmp-1] == '\r') { - - // If this is a \r\n or \n\r, skip the newlines. - if ((Ptr[SizeTmp] == '\r' || Ptr[SizeTmp] == '\n') && - Ptr[SizeTmp-1] != Ptr[SizeTmp]) - ++SizeTmp; - - // Found backslash. Parse the char after it. - Size += SizeTmp; - Ptr += SizeTmp; - - // Use slow version to accumulate a correct size field. - return getCharAndSizeSlowNoWarn(Ptr, Size, Features); - } - } while (isWhitespace(Ptr[SizeTmp])); - } - - // Otherwise, this is not an escaped newline, just return the slash. - return '\\'; - } - - // If this is a trigraph, process it. - if (Features.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') { - // If this is actually a legal trigraph (not something like "??x"), return - // it. - if (char C = GetTrigraphCharForLetter(Ptr[2])) { - Ptr += 3; - Size += 3; - if (C == '\\') goto Slash; - return C; - } - } - - // If this is neither, return a single character. - ++Size; - return *Ptr; -} - -//===----------------------------------------------------------------------===// -// Helper methods for lexing. -//===----------------------------------------------------------------------===// - -void Lexer::LexIdentifier(Token &Result, const char *CurPtr) { - // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] - unsigned Size; - unsigned char C = *CurPtr++; - while (isIdentifierBody(C)) { - C = *CurPtr++; - } - --CurPtr; // Back up over the skipped character. - - // Fast path, no $,\,? in identifier found. '\' might be an escaped newline - // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN. - // FIXME: UCNs. - if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) { -FinishIdentifier: - const char *IdStart = BufferPtr; - FormTokenWithChars(Result, CurPtr); - Result.setKind(tok::identifier); - - // If we are in raw mode, return this identifier raw. There is no need to - // look up identifier information or attempt to macro expand it. - if (LexingRawMode) return; - - // Fill in Result.IdentifierInfo, looking up the identifier in the - // identifier table. - PP->LookUpIdentifierInfo(Result, IdStart); - - // Finally, now that we know we have an identifier, pass this off to the - // preprocessor, which may macro expand it or something. - return PP->HandleIdentifier(Result); - } - - // Otherwise, $,\,? in identifier found. Enter slower path. - - C = getCharAndSize(CurPtr, Size); - while (1) { - if (C == '$') { - // If we hit a $ and they are not supported in identifiers, we are done. - if (!Features.DollarIdents) goto FinishIdentifier; - - // Otherwise, emit a diagnostic and continue. - Diag(CurPtr, diag::ext_dollar_in_identifier); - CurPtr = ConsumeChar(CurPtr, Size, Result); - C = getCharAndSize(CurPtr, Size); - continue; - } else if (!isIdentifierBody(C)) { // FIXME: UCNs. - // Found end of identifier. - goto FinishIdentifier; - } - - // Otherwise, this character is good, consume it. - CurPtr = ConsumeChar(CurPtr, Size, Result); - - C = getCharAndSize(CurPtr, Size); - while (isIdentifierBody(C)) { // FIXME: UCNs. - CurPtr = ConsumeChar(CurPtr, Size, Result); - C = getCharAndSize(CurPtr, Size); - } - } -} - - -/// LexNumericConstant - Lex the remainer of a integer or floating point -/// constant. From[-1] is the first character lexed. Return the end of the -/// constant. -void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { - unsigned Size; - char C = getCharAndSize(CurPtr, Size); - char PrevCh = 0; - while (isNumberBody(C)) { // FIXME: UCNs? - CurPtr = ConsumeChar(CurPtr, Size, Result); - PrevCh = C; - C = getCharAndSize(CurPtr, Size); - } - - // If we fell out, check for a sign, due to 1e+12. If we have one, continue. - if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) - return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); - - // If we have a hex FP constant, continue. - if (Features.HexFloats && - (C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) - return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); - - Result.setKind(tok::numeric_constant); - - // Update the location of token as well as BufferPtr. - FormTokenWithChars(Result, CurPtr); -} - -/// LexStringLiteral - Lex the remainder of a string literal, after having lexed -/// either " or L". -void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide){ - const char *NulCharacter = 0; // Does this string contain the \0 character? - - char C = getAndAdvanceChar(CurPtr, Result); - while (C != '"') { - // Skip escaped characters. - if (C == '\\') { - // Skip the escaped character. - C = getAndAdvanceChar(CurPtr, Result); - } else if (C == '\n' || C == '\r' || // Newline. - (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!LexingRawMode) Diag(BufferPtr, diag::err_unterminated_string); - Result.setKind(tok::unknown); - FormTokenWithChars(Result, CurPtr-1); - return; - } else if (C == 0) { - NulCharacter = CurPtr-1; - } - C = getAndAdvanceChar(CurPtr, Result); - } - - // If a nul character existed in the string, warn about it. - if (NulCharacter) Diag(NulCharacter, diag::null_in_string); - - Result.setKind(Wide ? tok::wide_string_literal : tok::string_literal); - - // Update the location of the token as well as the BufferPtr instance var. - FormTokenWithChars(Result, CurPtr); -} - -/// LexAngledStringLiteral - Lex the remainder of an angled string literal, -/// after having lexed the '<' character. This is used for #include filenames. -void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) { - const char *NulCharacter = 0; // Does this string contain the \0 character? - - char C = getAndAdvanceChar(CurPtr, Result); - while (C != '>') { - // Skip escaped characters. - if (C == '\\') { - // Skip the escaped character. - C = getAndAdvanceChar(CurPtr, Result); - } else if (C == '\n' || C == '\r' || // Newline. - (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!LexingRawMode) Diag(BufferPtr, diag::err_unterminated_string); - Result.setKind(tok::unknown); - FormTokenWithChars(Result, CurPtr-1); - return; - } else if (C == 0) { - NulCharacter = CurPtr-1; - } - C = getAndAdvanceChar(CurPtr, Result); - } - - // If a nul character existed in the string, warn about it. - if (NulCharacter) Diag(NulCharacter, diag::null_in_string); - - Result.setKind(tok::angle_string_literal); - - // Update the location of token as well as BufferPtr. - FormTokenWithChars(Result, CurPtr); -} - - -/// LexCharConstant - Lex the remainder of a character constant, after having -/// lexed either ' or L'. -void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { - const char *NulCharacter = 0; // Does this character contain the \0 character? - - // Handle the common case of 'x' and '\y' efficiently. - char C = getAndAdvanceChar(CurPtr, Result); - if (C == '\'') { - if (!LexingRawMode) Diag(BufferPtr, diag::err_empty_character); - Result.setKind(tok::unknown); - FormTokenWithChars(Result, CurPtr); - return; - } else if (C == '\\') { - // Skip the escaped character. - // FIXME: UCN's. - C = getAndAdvanceChar(CurPtr, Result); - } - - if (C && C != '\n' && C != '\r' && CurPtr[0] == '\'') { - ++CurPtr; - } else { - // Fall back on generic code for embedded nulls, newlines, wide chars. - do { - // Skip escaped characters. - if (C == '\\') { - // Skip the escaped character. - C = getAndAdvanceChar(CurPtr, Result); - } else if (C == '\n' || C == '\r' || // Newline. - (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!LexingRawMode) Diag(BufferPtr, diag::err_unterminated_char); - Result.setKind(tok::unknown); - FormTokenWithChars(Result, CurPtr-1); - return; - } else if (C == 0) { - NulCharacter = CurPtr-1; - } - C = getAndAdvanceChar(CurPtr, Result); - } while (C != '\''); - } - - if (NulCharacter) Diag(NulCharacter, diag::null_in_char); - - Result.setKind(tok::char_constant); - - // Update the location of token as well as BufferPtr. - FormTokenWithChars(Result, CurPtr); -} - -/// SkipWhitespace - Efficiently skip over a series of whitespace characters. -/// Update BufferPtr to point to the next non-whitespace character and return. -void Lexer::SkipWhitespace(Token &Result, const char *CurPtr) { - // Whitespace - Skip it, then return the token after the whitespace. - unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently. - while (1) { - // Skip horizontal whitespace very aggressively. - while (isHorizontalWhitespace(Char)) - Char = *++CurPtr; - - // Otherwise if we something other than whitespace, we're done. - if (Char != '\n' && Char != '\r') - break; - - if (ParsingPreprocessorDirective) { - // End of preprocessor directive line, let LexTokenInternal handle this. - BufferPtr = CurPtr; - return; - } - - // ok, but handle newline. - // The returned token is at the start of the line. - Result.setFlag(Token::StartOfLine); - // No leading whitespace seen so far. - Result.clearFlag(Token::LeadingSpace); - Char = *++CurPtr; - } - - // If this isn't immediately after a newline, there is leading space. - char PrevChar = CurPtr[-1]; - if (PrevChar != '\n' && PrevChar != '\r') - Result.setFlag(Token::LeadingSpace); - - BufferPtr = CurPtr; -} - -// SkipBCPLComment - We have just read the // characters from input. Skip until -// we find the newline character thats terminate the comment. Then update -/// BufferPtr and return. -bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { - // If BCPL comments aren't explicitly enabled for this language, emit an - // extension warning. - if (!Features.BCPLComment) { - Diag(BufferPtr, diag::ext_bcpl_comment); - - // Mark them enabled so we only emit one warning for this translation - // unit. - Features.BCPLComment = true; - } - - // Scan over the body of the comment. The common case, when scanning, is that - // the comment contains normal ascii characters with nothing interesting in - // them. As such, optimize for this case with the inner loop. - char C; - do { - C = *CurPtr; - // FIXME: Speedup BCPL comment lexing. Just scan for a \n or \r character. - // If we find a \n character, scan backwards, checking to see if it's an - // escaped newline, like we do for block comments. - - // Skip over characters in the fast loop. - while (C != 0 && // Potentially EOF. - C != '\\' && // Potentially escaped newline. - C != '?' && // Potentially trigraph. - C != '\n' && C != '\r') // Newline or DOS-style newline. - C = *++CurPtr; - - // If this is a newline, we're done. - if (C == '\n' || C == '\r') - break; // Found the newline? Break out! - - // Otherwise, this is a hard case. Fall back on getAndAdvanceChar to - // properly decode the character. - const char *OldPtr = CurPtr; - C = getAndAdvanceChar(CurPtr, Result); - - // If we read multiple characters, and one of those characters was a \r or - // \n, then we had an escaped newline within the comment. Emit diagnostic - // unless the next line is also a // comment. - if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') { - for (; OldPtr != CurPtr; ++OldPtr) - if (OldPtr[0] == '\n' || OldPtr[0] == '\r') { - // Okay, we found a // comment that ends in a newline, if the next - // line is also a // comment, but has spaces, don't emit a diagnostic. - if (isspace(C)) { - const char *ForwardPtr = CurPtr; - while (isspace(*ForwardPtr)) // Skip whitespace. - ++ForwardPtr; - if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/') - break; - } - - Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment); - break; - } - } - - if (CurPtr == BufferEnd+1) { --CurPtr; break; } - } while (C != '\n' && C != '\r'); - - // Found but did not consume the newline. - - // If we are returning comments as tokens, return this comment as a token. - if (KeepCommentMode) - return SaveBCPLComment(Result, CurPtr); - - // If we are inside a preprocessor directive and we see the end of line, - // return immediately, so that the lexer can return this as an EOM token. - if (ParsingPreprocessorDirective || CurPtr == BufferEnd) { - BufferPtr = CurPtr; - return true; - } - - // Otherwise, eat the \n character. We don't care if this is a \n\r or - // \r\n sequence. - ++CurPtr; - - // The next returned token is at the start of the line. - Result.setFlag(Token::StartOfLine); - // No leading whitespace seen so far. - Result.clearFlag(Token::LeadingSpace); - BufferPtr = CurPtr; - return true; -} - -/// SaveBCPLComment - If in save-comment mode, package up this BCPL comment in -/// an appropriate way and return it. -bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) { - Result.setKind(tok::comment); - FormTokenWithChars(Result, CurPtr); - - // If this BCPL-style comment is in a macro definition, transmogrify it into - // a C-style block comment. - if (ParsingPreprocessorDirective) { - std::string Spelling = PP->getSpelling(Result); - assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?"); - Spelling[1] = '*'; // Change prefix to "/*". - Spelling += "*/"; // add suffix. - - Result.setLocation(PP->CreateString(&Spelling[0], Spelling.size(), - Result.getLocation())); - Result.setLength(Spelling.size()); - } - return false; -} - -/// isBlockCommentEndOfEscapedNewLine - Return true if the specified newline -/// character (either \n or \r) is part of an escaped newline sequence. Issue a -/// diagnostic if so. We know that the is inside of a block comment. -static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, - Lexer *L) { - assert(CurPtr[0] == '\n' || CurPtr[0] == '\r'); - - // Back up off the newline. - --CurPtr; - - // If this is a two-character newline sequence, skip the other character. - if (CurPtr[0] == '\n' || CurPtr[0] == '\r') { - // \n\n or \r\r -> not escaped newline. - if (CurPtr[0] == CurPtr[1]) - return false; - // \n\r or \r\n -> skip the newline. - --CurPtr; - } - - // If we have horizontal whitespace, skip over it. We allow whitespace - // between the slash and newline. - bool HasSpace = false; - while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) { - --CurPtr; - HasSpace = true; - } - - // If we have a slash, we know this is an escaped newline. - if (*CurPtr == '\\') { - if (CurPtr[-1] != '*') return false; - } else { - // It isn't a slash, is it the ?? / trigraph? - if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' || - CurPtr[-3] != '*') - return false; - - // This is the trigraph ending the comment. Emit a stern warning! - CurPtr -= 2; - - // If no trigraphs are enabled, warn that we ignored this trigraph and - // ignore this * character. - if (!L->getFeatures().Trigraphs) { - L->Diag(CurPtr, diag::trigraph_ignored_block_comment); - return false; - } - L->Diag(CurPtr, diag::trigraph_ends_block_comment); - } - - // Warn about having an escaped newline between the */ characters. - L->Diag(CurPtr, diag::escaped_newline_block_comment_end); - - // If there was space between the backslash and newline, warn about it. - if (HasSpace) L->Diag(CurPtr, diag::backslash_newline_space); - - return true; -} - -#ifdef __SSE2__ -#include -#elif __ALTIVEC__ -#include -#undef bool -#endif - -/// SkipBlockComment - We have just read the /* characters from input. Read -/// until we find the */ characters that terminate the comment. Note that we -/// don't bother decoding trigraphs or escaped newlines in block comments, -/// because they cannot cause the comment to end. The only thing that can -/// happen is the comment could end with an escaped newline between the */ end -/// of comment. -bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { - // Scan one character past where we should, looking for a '/' character. Once - // we find it, check to see if it was preceeded by a *. This common - // optimization helps people who like to put a lot of * characters in their - // comments. - - // The first character we get with newlines and trigraphs skipped to handle - // the degenerate /*/ case below correctly if the * has an escaped newline - // after it. - unsigned CharSize; - unsigned char C = getCharAndSize(CurPtr, CharSize); - CurPtr += CharSize; - if (C == 0 && CurPtr == BufferEnd+1) { - Diag(BufferPtr, diag::err_unterminated_block_comment); - BufferPtr = CurPtr-1; - return true; - } - - // Check to see if the first character after the '/*' is another /. If so, - // then this slash does not end the block comment, it is part of it. - if (C == '/') - C = *CurPtr++; - - while (1) { - // Skip over all non-interesting characters until we find end of buffer or a - // (probably ending) '/' character. - if (CurPtr + 24 < BufferEnd) { - // While not aligned to a 16-byte boundary. - while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0) - C = *CurPtr++; - - if (C == '/') goto FoundSlash; - -#ifdef __SSE2__ - __m128i Slashes = _mm_set_epi8('/', '/', '/', '/', '/', '/', '/', '/', - '/', '/', '/', '/', '/', '/', '/', '/'); - while (CurPtr+16 <= BufferEnd && - _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes)) == 0) - CurPtr += 16; -#elif __ALTIVEC__ - __vector unsigned char Slashes = { - '/', '/', '/', '/', '/', '/', '/', '/', - '/', '/', '/', '/', '/', '/', '/', '/' - }; - while (CurPtr+16 <= BufferEnd && - !vec_any_eq(*(vector unsigned char*)CurPtr, Slashes)) - CurPtr += 16; -#else - // Scan for '/' quickly. Many block comments are very large. - while (CurPtr[0] != '/' && - CurPtr[1] != '/' && - CurPtr[2] != '/' && - CurPtr[3] != '/' && - CurPtr+4 < BufferEnd) { - CurPtr += 4; - } -#endif - - // It has to be one of the bytes scanned, increment to it and read one. - C = *CurPtr++; - } - - // Loop to scan the remainder. - while (C != '/' && C != '\0') - C = *CurPtr++; - - FoundSlash: - if (C == '/') { - if (CurPtr[-2] == '*') // We found the final */. We're done! - break; - - if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) { - if (isEndOfBlockCommentWithEscapedNewLine(CurPtr-2, this)) { - // We found the final */, though it had an escaped newline between the - // * and /. We're done! - break; - } - } - if (CurPtr[0] == '*' && CurPtr[1] != '/') { - // If this is a /* inside of the comment, emit a warning. Don't do this - // if this is a /*/, which will end the comment. This misses cases with - // embedded escaped newlines, but oh well. - Diag(CurPtr-1, diag::nested_block_comment); - } - } else if (C == 0 && CurPtr == BufferEnd+1) { - Diag(BufferPtr, diag::err_unterminated_block_comment); - // Note: the user probably forgot a */. We could continue immediately - // after the /*, but this would involve lexing a lot of what really is the - // comment, which surely would confuse the parser. - BufferPtr = CurPtr-1; - return true; - } - C = *CurPtr++; - } - - // If we are returning comments as tokens, return this comment as a token. - if (KeepCommentMode) { - Result.setKind(tok::comment); - FormTokenWithChars(Result, CurPtr); - return false; - } - - // It is common for the tokens immediately after a /**/ comment to be - // whitespace. Instead of going through the big switch, handle it - // efficiently now. - if (isHorizontalWhitespace(*CurPtr)) { - Result.setFlag(Token::LeadingSpace); - SkipWhitespace(Result, CurPtr+1); - return true; - } - - // Otherwise, just return so that the next character will be lexed as a token. - BufferPtr = CurPtr; - Result.setFlag(Token::LeadingSpace); - return true; -} - -//===----------------------------------------------------------------------===// -// Primary Lexing Entry Points -//===----------------------------------------------------------------------===// - -/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and -/// (potentially) macro expand the filename. -void Lexer::LexIncludeFilename(Token &FilenameTok) { - assert(ParsingPreprocessorDirective && - ParsingFilename == false && - "Must be in a preprocessing directive!"); - - // We are now parsing a filename! - ParsingFilename = true; - - // Lex the filename. - Lex(FilenameTok); - - // We should have obtained the filename now. - ParsingFilename = false; - - // No filename? - if (FilenameTok.is(tok::eom)) - Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); -} - -/// ReadToEndOfLine - Read the rest of the current preprocessor line as an -/// uninterpreted string. This switches the lexer out of directive mode. -std::string Lexer::ReadToEndOfLine() { - assert(ParsingPreprocessorDirective && ParsingFilename == false && - "Must be in a preprocessing directive!"); - std::string Result; - Token Tmp; - - // CurPtr - Cache BufferPtr in an automatic variable. - const char *CurPtr = BufferPtr; - while (1) { - char Char = getAndAdvanceChar(CurPtr, Tmp); - switch (Char) { - default: - Result += Char; - break; - case 0: // Null. - // Found end of file? - if (CurPtr-1 != BufferEnd) { - // Nope, normal character, continue. - Result += Char; - break; - } - // FALL THROUGH. - case '\r': - case '\n': - // Okay, we found the end of the line. First, back up past the \0, \r, \n. - assert(CurPtr[-1] == Char && "Trigraphs for newline?"); - BufferPtr = CurPtr-1; - - // Next, lex the character, which should handle the EOM transition. - Lex(Tmp); - assert(Tmp.is(tok::eom) && "Unexpected token!"); - - // Finally, we're done, return the string we found. - return Result; - } - } -} - -/// LexEndOfFile - CurPtr points to the end of this file. Handle this -/// condition, reporting diagnostics and handling other edge cases as required. -/// This returns true if Result contains a token, false if PP.Lex should be -/// called again. -bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { - // If we hit the end of the file while parsing a preprocessor directive, - // end the preprocessor directive first. The next token returned will - // then be the end of file. - if (ParsingPreprocessorDirective) { - // Done parsing the "line". - ParsingPreprocessorDirective = false; - Result.setKind(tok::eom); - // Update the location of token as well as BufferPtr. - FormTokenWithChars(Result, CurPtr); - - // Restore comment saving mode, in case it was disabled for directive. - KeepCommentMode = PP->getCommentRetentionState(); - return true; // Have a token. - } - - // If we are in raw mode, return this event as an EOF token. Let the caller - // that put us in raw mode handle the event. - if (LexingRawMode) { - Result.startToken(); - BufferPtr = BufferEnd; - FormTokenWithChars(Result, BufferEnd); - Result.setKind(tok::eof); - return true; - } - - // Otherwise, issue diagnostics for unterminated #if and missing newline. - - // If we are in a #if directive, emit an error. - while (!ConditionalStack.empty()) { - Diag(ConditionalStack.back().IfLoc, diag::err_pp_unterminated_conditional); - ConditionalStack.pop_back(); - } - - // If the file was empty or didn't end in a newline, issue a pedwarn. - if (CurPtr[-1] != '\n' && CurPtr[-1] != '\r') - Diag(BufferEnd, diag::ext_no_newline_eof); - - BufferPtr = CurPtr; - - // Finally, let the preprocessor handle this. - return PP->HandleEndOfFile(Result); -} - -/// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from -/// the specified lexer will return a tok::l_paren token, 0 if it is something -/// else and 2 if there are no more tokens in the buffer controlled by the -/// lexer. -unsigned Lexer::isNextPPTokenLParen() { - assert(!LexingRawMode && "How can we expand a macro from a skipping buffer?"); - - // Switch to 'skipping' mode. This will ensure that we can lex a token - // without emitting diagnostics, disables macro expansion, and will cause EOF - // to return an EOF token instead of popping the include stack. - LexingRawMode = true; - - // Save state that can be changed while lexing so that we can restore it. - const char *TmpBufferPtr = BufferPtr; - - Token Tok; - Tok.startToken(); - LexTokenInternal(Tok); - - // Restore state that may have changed. - BufferPtr = TmpBufferPtr; - - // Restore the lexer back to non-skipping mode. - LexingRawMode = false; - - if (Tok.is(tok::eof)) - return 2; - return Tok.is(tok::l_paren); -} - - -/// LexTokenInternal - This implements a simple C family lexer. It is an -/// extremely performance critical piece of code. This assumes that the buffer -/// has a null character at the end of the file. Return true if an error -/// occurred and compilation should terminate, false if normal. This returns a -/// preprocessing token, not a normal token, as such, it is an internal -/// interface. It assumes that the Flags of result have been cleared before -/// calling this. -void Lexer::LexTokenInternal(Token &Result) { -LexNextToken: - // New token, can't need cleaning yet. - Result.clearFlag(Token::NeedsCleaning); - Result.setIdentifierInfo(0); - - // CurPtr - Cache BufferPtr in an automatic variable. - const char *CurPtr = BufferPtr; - - // Small amounts of horizontal whitespace is very common between tokens. - if ((*CurPtr == ' ') || (*CurPtr == '\t')) { - ++CurPtr; - while ((*CurPtr == ' ') || (*CurPtr == '\t')) - ++CurPtr; - BufferPtr = CurPtr; - Result.setFlag(Token::LeadingSpace); - } - - unsigned SizeTmp, SizeTmp2; // Temporaries for use in cases below. - - // Read a character, advancing over it. - char Char = getAndAdvanceChar(CurPtr, Result); - switch (Char) { - case 0: // Null. - // Found end of file? - if (CurPtr-1 == BufferEnd) { - // Read the PP instance variable into an automatic variable, because - // LexEndOfFile will often delete 'this'. - Preprocessor *PPCache = PP; - if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file. - return; // Got a token to return. - assert(PPCache && "Raw buffer::LexEndOfFile should return a token"); - return PPCache->Lex(Result); - } - - Diag(CurPtr-1, diag::null_in_file); - Result.setFlag(Token::LeadingSpace); - SkipWhitespace(Result, CurPtr); - goto LexNextToken; // GCC isn't tail call eliminating. - case '\n': - case '\r': - // If we are inside a preprocessor directive and we see the end of line, - // we know we are done with the directive, so return an EOM token. - if (ParsingPreprocessorDirective) { - // Done parsing the "line". - ParsingPreprocessorDirective = false; - - // Restore comment saving mode, in case it was disabled for directive. - KeepCommentMode = PP->getCommentRetentionState(); - - // Since we consumed a newline, we are back at the start of a line. - IsAtStartOfLine = true; - - Result.setKind(tok::eom); - break; - } - // The returned token is at the start of the line. - Result.setFlag(Token::StartOfLine); - // No leading whitespace seen so far. - Result.clearFlag(Token::LeadingSpace); - SkipWhitespace(Result, CurPtr); - goto LexNextToken; // GCC isn't tail call eliminating. - case ' ': - case '\t': - case '\f': - case '\v': - SkipHorizontalWhitespace: - Result.setFlag(Token::LeadingSpace); - SkipWhitespace(Result, CurPtr); - - SkipIgnoredUnits: - CurPtr = BufferPtr; - - // If the next token is obviously a // or /* */ comment, skip it efficiently - // too (without going through the big switch stmt). - if (CurPtr[0] == '/' && CurPtr[1] == '/' && !KeepCommentMode) { - SkipBCPLComment(Result, CurPtr+2); - goto SkipIgnoredUnits; - } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !KeepCommentMode) { - SkipBlockComment(Result, CurPtr+2); - goto SkipIgnoredUnits; - } else if (isHorizontalWhitespace(*CurPtr)) { - goto SkipHorizontalWhitespace; - } - goto LexNextToken; // GCC isn't tail call eliminating. - - // C99 6.4.4.1: Integer Constants. - // C99 6.4.4.2: Floating Constants. - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - return LexNumericConstant(Result, CurPtr); - - case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz"). - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - Char = getCharAndSize(CurPtr, SizeTmp); - - // Wide string literal. - if (Char == '"') - return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), - true); - - // Wide character constant. - if (Char == '\'') - return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result)); - // FALL THROUGH, treating L like the start of an identifier. - - // C99 6.4.2: Identifiers. - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': - case 'H': case 'I': case 'J': case 'K': /*'L'*/case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': - case 'V': case 'W': case 'X': case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': - case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': - case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': - case 'v': case 'w': case 'x': case 'y': case 'z': - case '_': - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); - - case '$': // $ in identifiers. - if (Features.DollarIdents) { - Diag(CurPtr-1, diag::ext_dollar_in_identifier); - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); - } - - Result.setKind(tok::unknown); - break; - - // C99 6.4.4: Character Constants. - case '\'': - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - return LexCharConstant(Result, CurPtr); - - // C99 6.4.5: String Literals. - case '"': - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - return LexStringLiteral(Result, CurPtr, false); - - // C99 6.4.6: Punctuators. - case '?': - Result.setKind(tok::question); - break; - case '[': - Result.setKind(tok::l_square); - break; - case ']': - Result.setKind(tok::r_square); - break; - case '(': - Result.setKind(tok::l_paren); - break; - case ')': - Result.setKind(tok::r_paren); - break; - case '{': - Result.setKind(tok::l_brace); - break; - case '}': - Result.setKind(tok::r_brace); - break; - case '.': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char >= '0' && Char <= '9') { - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - - return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result)); - } else if (Features.CPlusPlus && Char == '*') { - Result.setKind(tok::periodstar); - CurPtr += SizeTmp; - } else if (Char == '.' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') { - Result.setKind(tok::ellipsis); - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - } else { - Result.setKind(tok::period); - } - break; - case '&': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '&') { - Result.setKind(tok::ampamp); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '=') { - Result.setKind(tok::ampequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::amp); - } - break; - case '*': - if (getCharAndSize(CurPtr, SizeTmp) == '=') { - Result.setKind(tok::starequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::star); - } - break; - case '+': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '+') { - Result.setKind(tok::plusplus); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '=') { - Result.setKind(tok::plusequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::plus); - } - break; - case '-': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '-') { - Result.setKind(tok::minusminus); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '>' && Features.CPlusPlus && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { - Result.setKind(tok::arrowstar); // C++ ->* - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - } else if (Char == '>') { - Result.setKind(tok::arrow); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '=') { - Result.setKind(tok::minusequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::minus); - } - break; - case '~': - Result.setKind(tok::tilde); - break; - case '!': - if (getCharAndSize(CurPtr, SizeTmp) == '=') { - Result.setKind(tok::exclaimequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::exclaim); - } - break; - case '/': - // 6.4.9: Comments - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '/') { // BCPL comment. - if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) { - // It is common for the tokens immediately after a // comment to be - // whitespace (indentation for the next line). Instead of going through - // the big switch, handle it efficiently now. - goto SkipIgnoredUnits; - } - return; // KeepCommentMode - } else if (Char == '*') { // /**/ comment. - if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) - goto LexNextToken; // GCC isn't tail call eliminating. - return; // KeepCommentMode - } else if (Char == '=') { - Result.setKind(tok::slashequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::slash); - } - break; - case '%': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '=') { - Result.setKind(tok::percentequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Features.Digraphs && Char == '>') { - Result.setKind(tok::r_brace); // '%>' -> '}' - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Features.Digraphs && Char == ':') { - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') { - Result.setKind(tok::hashhash); // '%:%:' -> '##' - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - } else if (Char == '@' && Features.Microsoft) { // %:@ -> #@ -> Charize - Result.setKind(tok::hashat); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - Diag(BufferPtr, diag::charize_microsoft_ext); - } else { - Result.setKind(tok::hash); // '%:' -> '#' - - // We parsed a # character. If this occurs at the start of the line, - // it's actually the start of a preprocessing directive. Callback to - // the preprocessor to handle it. - // FIXME: -fpreprocessed mode?? - if (Result.isAtStartOfLine() && !LexingRawMode) { - BufferPtr = CurPtr; - PP->HandleDirective(Result); - - // As an optimization, if the preprocessor didn't switch lexers, tail - // recurse. - if (PP->isCurrentLexer(this)) { - // Start a new token. If this is a #include or something, the PP may - // want us starting at the beginning of the line again. If so, set - // the StartOfLine flag. - if (IsAtStartOfLine) { - Result.setFlag(Token::StartOfLine); - IsAtStartOfLine = false; - } - goto LexNextToken; // GCC isn't tail call eliminating. - } - - return PP->Lex(Result); - } - } - } else { - Result.setKind(tok::percent); - } - break; - case '<': - Char = getCharAndSize(CurPtr, SizeTmp); - if (ParsingFilename) { - return LexAngledStringLiteral(Result, CurPtr+SizeTmp); - } else if (Char == '<' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { - Result.setKind(tok::lesslessequal); - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - } else if (Char == '<') { - Result.setKind(tok::lessless); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '=') { - Result.setKind(tok::lessequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Features.Digraphs && Char == ':') { - Result.setKind(tok::l_square); // '<:' -> '[' - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Features.Digraphs && Char == '%') { - Result.setKind(tok::l_brace); // '<%' -> '{' - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::less); - } - break; - case '>': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '=') { - Result.setKind(tok::greaterequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '>' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { - Result.setKind(tok::greatergreaterequal); - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - } else if (Char == '>') { - Result.setKind(tok::greatergreater); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::greater); - } - break; - case '^': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '=') { - Result.setKind(tok::caretequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::caret); - } - break; - case '|': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '=') { - Result.setKind(tok::pipeequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '|') { - Result.setKind(tok::pipepipe); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::pipe); - } - break; - case ':': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Features.Digraphs && Char == '>') { - Result.setKind(tok::r_square); // ':>' -> ']' - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Features.CPlusPlus && Char == ':') { - Result.setKind(tok::coloncolon); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::colon); - } - break; - case ';': - Result.setKind(tok::semi); - break; - case '=': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '=') { - Result.setKind(tok::equalequal); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::equal); - } - break; - case ',': - Result.setKind(tok::comma); - break; - case '#': - Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '#') { - Result.setKind(tok::hashhash); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else if (Char == '@' && Features.Microsoft) { // #@ -> Charize - Result.setKind(tok::hashat); - Diag(BufferPtr, diag::charize_microsoft_ext); - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - } else { - Result.setKind(tok::hash); - // We parsed a # character. If this occurs at the start of the line, - // it's actually the start of a preprocessing directive. Callback to - // the preprocessor to handle it. - // FIXME: -fpreprocessed mode?? - if (Result.isAtStartOfLine() && !LexingRawMode) { - BufferPtr = CurPtr; - PP->HandleDirective(Result); - - // As an optimization, if the preprocessor didn't switch lexers, tail - // recurse. - if (PP->isCurrentLexer(this)) { - // Start a new token. If this is a #include or something, the PP may - // want us starting at the beginning of the line again. If so, set - // the StartOfLine flag. - if (IsAtStartOfLine) { - Result.setFlag(Token::StartOfLine); - IsAtStartOfLine = false; - } - goto LexNextToken; // GCC isn't tail call eliminating. - } - return PP->Lex(Result); - } - } - break; - - case '@': - // Objective C support. - if (CurPtr[-1] == '@' && Features.ObjC1) - Result.setKind(tok::at); - else - Result.setKind(tok::unknown); - break; - - case '\\': - // FIXME: UCN's. - // FALL THROUGH. - default: - Result.setKind(tok::unknown); - break; - } - - // Notify MIOpt that we read a non-whitespace/non-comment token. - MIOpt.ReadToken(); - - // Update the location of token as well as BufferPtr. - FormTokenWithChars(Result, CurPtr); -} diff --git a/clang/Lex/LiteralSupport.cpp b/clang/Lex/LiteralSupport.cpp deleted file mode 100644 index aa0b831af90..00000000000 --- a/clang/Lex/LiteralSupport.cpp +++ /dev/null @@ -1,691 +0,0 @@ -//===--- LiteralSupport.cpp - Code to parse and process literals ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the NumericLiteralParser, CharLiteralParser, and -// StringLiteralParser interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/LiteralSupport.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/StringExtras.h" -using namespace clang; - -/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's -/// not valid. -static int HexDigitValue(char C) { - if (C >= '0' && C <= '9') return C-'0'; - if (C >= 'a' && C <= 'f') return C-'a'+10; - if (C >= 'A' && C <= 'F') return C-'A'+10; - return -1; -} - -/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in -/// either a character or a string literal. -static unsigned ProcessCharEscape(const char *&ThisTokBuf, - const char *ThisTokEnd, bool &HadError, - SourceLocation Loc, bool IsWide, - Preprocessor &PP) { - // Skip the '\' char. - ++ThisTokBuf; - - // We know that this character can't be off the end of the buffer, because - // that would have been \", which would not have been the end of string. - unsigned ResultChar = *ThisTokBuf++; - switch (ResultChar) { - // These map to themselves. - case '\\': case '\'': case '"': case '?': break; - - // These have fixed mappings. - case 'a': - // TODO: K&R: the meaning of '\\a' is different in traditional C - ResultChar = 7; - break; - case 'b': - ResultChar = 8; - break; - case 'e': - PP.Diag(Loc, diag::ext_nonstandard_escape, "e"); - ResultChar = 27; - break; - case 'f': - ResultChar = 12; - break; - case 'n': - ResultChar = 10; - break; - case 'r': - ResultChar = 13; - break; - case 't': - ResultChar = 9; - break; - case 'v': - ResultChar = 11; - break; - - //case 'u': case 'U': // FIXME: UCNs. - case 'x': { // Hex escape. - ResultChar = 0; - if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) { - PP.Diag(Loc, diag::err_hex_escape_no_digits); - HadError = 1; - break; - } - - // Hex escapes are a maximal series of hex digits. - bool Overflow = false; - for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) { - int CharVal = HexDigitValue(ThisTokBuf[0]); - if (CharVal == -1) break; - Overflow |= (ResultChar & 0xF0000000) ? true : false; // About to shift out a digit? - ResultChar <<= 4; - ResultChar |= CharVal; - } - - // See if any bits will be truncated when evaluated as a character. - unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide); - - if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { - Overflow = true; - ResultChar &= ~0U >> (32-CharWidth); - } - - // Check for overflow. - if (Overflow) // Too many digits to fit in - PP.Diag(Loc, diag::warn_hex_escape_too_large); - break; - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': { - // Octal escapes. - --ThisTokBuf; - ResultChar = 0; - - // Octal escapes are a series of octal digits with maximum length 3. - // "\0123" is a two digit sequence equal to "\012" "3". - unsigned NumDigits = 0; - do { - ResultChar <<= 3; - ResultChar |= *ThisTokBuf++ - '0'; - ++NumDigits; - } while (ThisTokBuf != ThisTokEnd && NumDigits < 3 && - ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7'); - - // Check for overflow. Reject '\777', but not L'\777'. - unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide); - - if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { - PP.Diag(Loc, diag::warn_octal_escape_too_large); - ResultChar &= ~0U >> (32-CharWidth); - } - break; - } - - // Otherwise, these are not valid escapes. - case '(': case '{': case '[': case '%': - // GCC accepts these as extensions. We warn about them as such though. - if (!PP.getLangOptions().NoExtensions) { - PP.Diag(Loc, diag::ext_nonstandard_escape, - std::string()+(char)ResultChar); - break; - } - // FALL THROUGH. - default: - if (isgraph(ThisTokBuf[0])) { - PP.Diag(Loc, diag::ext_unknown_escape, std::string()+(char)ResultChar); - } else { - PP.Diag(Loc, diag::ext_unknown_escape, "x"+llvm::utohexstr(ResultChar)); - } - break; - } - - return ResultChar; -} - - - - -/// integer-constant: [C99 6.4.4.1] -/// decimal-constant integer-suffix -/// octal-constant integer-suffix -/// hexadecimal-constant integer-suffix -/// decimal-constant: -/// nonzero-digit -/// decimal-constant digit -/// octal-constant: -/// 0 -/// octal-constant octal-digit -/// hexadecimal-constant: -/// hexadecimal-prefix hexadecimal-digit -/// hexadecimal-constant hexadecimal-digit -/// hexadecimal-prefix: one of -/// 0x 0X -/// integer-suffix: -/// unsigned-suffix [long-suffix] -/// unsigned-suffix [long-long-suffix] -/// long-suffix [unsigned-suffix] -/// long-long-suffix [unsigned-sufix] -/// nonzero-digit: -/// 1 2 3 4 5 6 7 8 9 -/// octal-digit: -/// 0 1 2 3 4 5 6 7 -/// hexadecimal-digit: -/// 0 1 2 3 4 5 6 7 8 9 -/// a b c d e f -/// A B C D E F -/// unsigned-suffix: one of -/// u U -/// long-suffix: one of -/// l L -/// long-long-suffix: one of -/// ll LL -/// -/// floating-constant: [C99 6.4.4.2] -/// TODO: add rules... -/// - -NumericLiteralParser:: -NumericLiteralParser(const char *begin, const char *end, - SourceLocation TokLoc, Preprocessor &pp) - : PP(pp), ThisTokBegin(begin), ThisTokEnd(end) { - s = DigitsBegin = begin; - saw_exponent = false; - saw_period = false; - isLong = false; - isUnsigned = false; - isLongLong = false; - isFloat = false; - isImaginary = false; - hadError = false; - - if (*s == '0') { // parse radix - s++; - if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) { - s++; - radix = 16; - DigitsBegin = s; - s = SkipHexDigits(s); - if (s == ThisTokEnd) { - // Done. - } else if (*s == '.') { - s++; - saw_period = true; - s = SkipHexDigits(s); - } - // A binary exponent can appear with or with a '.'. If dotted, the - // binary exponent is required. - if ((*s == 'p' || *s == 'P') && PP.getLangOptions().HexFloats) { - s++; - saw_exponent = true; - if (*s == '+' || *s == '-') s++; // sign - const char *first_non_digit = SkipDigits(s); - if (first_non_digit == s) { - Diag(TokLoc, diag::err_exponent_has_no_digits); - return; - } else { - s = first_non_digit; - } - } else if (saw_period) { - Diag(TokLoc, diag::err_hexconstant_requires_exponent); - return; - } - } else if (*s == 'b' || *s == 'B') { - // 0b101010 is a GCC extension. - ++s; - radix = 2; - DigitsBegin = s; - s = SkipBinaryDigits(s); - if (s == ThisTokEnd) { - // Done. - } else if (isxdigit(*s)) { - Diag(TokLoc, diag::err_invalid_binary_digit, std::string(s, s+1)); - return; - } - PP.Diag(TokLoc, diag::ext_binary_literal); - } else { - // For now, the radix is set to 8. If we discover that we have a - // floating point constant, the radix will change to 10. Octal floating - // point constants are not permitted (only decimal and hexadecimal). - radix = 8; - DigitsBegin = s; - s = SkipOctalDigits(s); - if (s == ThisTokEnd) { - // Done. - } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { - TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin); - Diag(TokLoc, diag::err_invalid_octal_digit, std::string(s, s+1)); - return; - } else if (*s == '.') { - s++; - radix = 10; - saw_period = true; - s = SkipDigits(s); - } - if (*s == 'e' || *s == 'E') { // exponent - s++; - radix = 10; - saw_exponent = true; - if (*s == '+' || *s == '-') s++; // sign - const char *first_non_digit = SkipDigits(s); - if (first_non_digit == s) { - Diag(TokLoc, diag::err_exponent_has_no_digits); - return; - } else { - s = first_non_digit; - } - } - } - } else { // the first digit is non-zero - radix = 10; - s = SkipDigits(s); - if (s == ThisTokEnd) { - // Done. - } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { - Diag(TokLoc, diag::err_invalid_decimal_digit, std::string(s, s+1)); - return; - } else if (*s == '.') { - s++; - saw_period = true; - s = SkipDigits(s); - } - if (*s == 'e' || *s == 'E') { // exponent - s++; - saw_exponent = true; - if (*s == '+' || *s == '-') s++; // sign - const char *first_non_digit = SkipDigits(s); - if (first_non_digit == s) { - Diag(TokLoc, diag::err_exponent_has_no_digits); - return; - } else { - s = first_non_digit; - } - } - } - - SuffixBegin = s; - - // Parse the suffix. At this point we can classify whether we have an FP or - // integer constant. - bool isFPConstant = isFloatingLiteral(); - - // Loop over all of the characters of the suffix. If we see something bad, - // we break out of the loop. - for (; s != ThisTokEnd; ++s) { - switch (*s) { - case 'f': // FP Suffix for "float" - case 'F': - if (!isFPConstant) break; // Error for integer constant. - if (isFloat || isLong) break; // FF, LF invalid. - isFloat = true; - continue; // Success. - case 'u': - case 'U': - if (isFPConstant) break; // Error for floating constant. - if (isUnsigned) break; // Cannot be repeated. - isUnsigned = true; - continue; // Success. - case 'l': - case 'L': - if (isLong || isLongLong) break; // Cannot be repeated. - if (isFloat) break; // LF invalid. - - // Check for long long. The L's need to be adjacent and the same case. - if (s+1 != ThisTokEnd && s[1] == s[0]) { - if (isFPConstant) break; // long long invalid for floats. - isLongLong = true; - ++s; // Eat both of them. - } else { - isLong = true; - } - continue; // Success. - case 'i': - case 'I': - case 'j': - case 'J': - if (isImaginary) break; // Cannot be repeated. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), - diag::ext_imaginary_constant); - isImaginary = true; - continue; // Success. - } - // If we reached here, there was an error. - break; - } - - // Report an error if there are any. - if (s != ThisTokEnd) { - TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin); - Diag(TokLoc, isFPConstant ? diag::err_invalid_suffix_float_constant : - diag::err_invalid_suffix_integer_constant, - std::string(SuffixBegin, ThisTokEnd)); - return; - } -} - -/// GetIntegerValue - Convert this numeric literal value to an APInt that -/// matches Val's input width. If there is an overflow, set Val to the low bits -/// of the result and return true. Otherwise, return false. -bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { - Val = 0; - s = DigitsBegin; - - llvm::APInt RadixVal(Val.getBitWidth(), radix); - llvm::APInt CharVal(Val.getBitWidth(), 0); - llvm::APInt OldVal = Val; - - bool OverflowOccurred = false; - while (s < SuffixBegin) { - unsigned C = HexDigitValue(*s++); - - // If this letter is out of bound for this radix, reject it. - assert(C < radix && "NumericLiteralParser ctor should have rejected this"); - - CharVal = C; - - // Add the digit to the value in the appropriate radix. If adding in digits - // made the value smaller, then this overflowed. - OldVal = Val; - - // Multiply by radix, did overflow occur on the multiply? - Val *= RadixVal; - OverflowOccurred |= Val.udiv(RadixVal) != OldVal; - - OldVal = Val; - // Add value, did overflow occur on the value? - Val += CharVal; - OverflowOccurred |= Val.ult(OldVal); - OverflowOccurred |= Val.ult(CharVal); - } - return OverflowOccurred; -} - -llvm::APFloat NumericLiteralParser:: -GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) { - using llvm::APFloat; - - llvm::SmallVector floatChars; - for (unsigned i = 0, n = ThisTokEnd-ThisTokBegin; i != n; ++i) - floatChars.push_back(ThisTokBegin[i]); - - floatChars.push_back('\0'); - - APFloat V (Format, APFloat::fcZero, false); - APFloat::opStatus status; - - status = V.convertFromString(&floatChars[0],APFloat::rmNearestTiesToEven); - - if (isExact) - *isExact = status == APFloat::opOK; - - return V; -} - -void NumericLiteralParser::Diag(SourceLocation Loc, unsigned DiagID, - const std::string &M) { - PP.Diag(Loc, DiagID, M); - hadError = true; -} - - -CharLiteralParser::CharLiteralParser(const char *begin, const char *end, - SourceLocation Loc, Preprocessor &PP) { - // At this point we know that the character matches the regex "L?'.*'". - HadError = false; - Value = 0; - - // Determine if this is a wide character. - IsWide = begin[0] == 'L'; - if (IsWide) ++begin; - - // Skip over the entry quote. - assert(begin[0] == '\'' && "Invalid token lexed"); - ++begin; - - // FIXME: This assumes that 'int' is 32-bits in overflow calculation, and the - // size of "value". - assert(PP.getTargetInfo().getIntWidth() == 32 && - "Assumes sizeof(int) == 4 for now"); - // FIXME: This assumes that wchar_t is 32-bits for now. - assert(PP.getTargetInfo().getWCharWidth() == 32 && - "Assumes sizeof(wchar_t) == 4 for now"); - // FIXME: This extensively assumes that 'char' is 8-bits. - assert(PP.getTargetInfo().getCharWidth() == 8 && - "Assumes char is 8 bits"); - - bool isFirstChar = true; - bool isMultiChar = false; - while (begin[0] != '\'') { - unsigned ResultChar; - if (begin[0] != '\\') // If this is a normal character, consume it. - ResultChar = *begin++; - else // Otherwise, this is an escape character. - ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP); - - // If this is a multi-character constant (e.g. 'abc'), handle it. These are - // implementation defined (C99 6.4.4.4p10). - if (!isFirstChar) { - // If this is the second character being processed, do special handling. - if (!isMultiChar) { - isMultiChar = true; - - // Warn about discarding the top bits for multi-char wide-character - // constants (L'abcd'). - if (IsWide) - PP.Diag(Loc, diag::warn_extraneous_wide_char_constant); - } - - if (IsWide) { - // Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'. - Value = 0; - } else { - // Narrow character literals act as though their value is concatenated - // in this implementation. - if (((Value << 8) >> 8) != Value) - PP.Diag(Loc, diag::warn_char_constant_too_large); - Value <<= 8; - } - } - - Value += ResultChar; - isFirstChar = false; - } - - // If this is a single narrow character, sign extend it (e.g. '\xFF' is "-1") - // if 'char' is signed for this target (C99 6.4.4.4p10). Note that multiple - // character constants are not sign extended in the this implementation: - // '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC. - if (!IsWide && !isMultiChar && (Value & 128) && - PP.getTargetInfo().isCharSigned()) - Value = (signed char)Value; -} - - -/// string-literal: [C99 6.4.5] -/// " [s-char-sequence] " -/// L" [s-char-sequence] " -/// s-char-sequence: -/// s-char -/// s-char-sequence s-char -/// s-char: -/// any source character except the double quote ", -/// backslash \, or newline character -/// escape-character -/// universal-character-name -/// escape-character: [C99 6.4.4.4] -/// \ escape-code -/// universal-character-name -/// escape-code: -/// character-escape-code -/// octal-escape-code -/// hex-escape-code -/// character-escape-code: one of -/// n t b r f v a -/// \ ' " ? -/// octal-escape-code: -/// octal-digit -/// octal-digit octal-digit -/// octal-digit octal-digit octal-digit -/// hex-escape-code: -/// x hex-digit -/// hex-escape-code hex-digit -/// universal-character-name: -/// \u hex-quad -/// \U hex-quad hex-quad -/// hex-quad: -/// hex-digit hex-digit hex-digit hex-digit -/// -StringLiteralParser:: -StringLiteralParser(const Token *StringToks, unsigned NumStringToks, - Preprocessor &pp, TargetInfo &t) - : PP(pp), Target(t) { - // Scan all of the string portions, remember the max individual token length, - // computing a bound on the concatenated string length, and see whether any - // piece is a wide-string. If any of the string portions is a wide-string - // literal, the result is a wide-string literal [C99 6.4.5p4]. - MaxTokenLength = StringToks[0].getLength(); - SizeBound = StringToks[0].getLength()-2; // -2 for "". - AnyWide = StringToks[0].is(tok::wide_string_literal); - - hadError = false; - - // Implement Translation Phase #6: concatenation of string literals - /// (C99 5.1.1.2p1). The common case is only one string fragment. - for (unsigned i = 1; i != NumStringToks; ++i) { - // The string could be shorter than this if it needs cleaning, but this is a - // reasonable bound, which is all we need. - SizeBound += StringToks[i].getLength()-2; // -2 for "". - - // Remember maximum string piece length. - if (StringToks[i].getLength() > MaxTokenLength) - MaxTokenLength = StringToks[i].getLength(); - - // Remember if we see any wide strings. - AnyWide |= StringToks[i].is(tok::wide_string_literal); - } - - - // Include space for the null terminator. - ++SizeBound; - - // TODO: K&R warning: "traditional C rejects string constant concatenation" - - // Get the width in bytes of wchar_t. If no wchar_t strings are used, do not - // query the target. As such, wchar_tByteWidth is only valid if AnyWide=true. - wchar_tByteWidth = ~0U; - if (AnyWide) { - wchar_tByteWidth = Target.getWCharWidth(); - assert((wchar_tByteWidth & 7) == 0 && "Assumes wchar_t is byte multiple!"); - wchar_tByteWidth /= 8; - } - - // The output buffer size needs to be large enough to hold wide characters. - // This is a worst-case assumption which basically corresponds to L"" "long". - if (AnyWide) - SizeBound *= wchar_tByteWidth; - - // Size the temporary buffer to hold the result string data. - ResultBuf.resize(SizeBound); - - // Likewise, but for each string piece. - llvm::SmallString<512> TokenBuf; - TokenBuf.resize(MaxTokenLength); - - // Loop over all the strings, getting their spelling, and expanding them to - // wide strings as appropriate. - ResultPtr = &ResultBuf[0]; // Next byte to fill in. - - Pascal = false; - - for (unsigned i = 0, e = NumStringToks; i != e; ++i) { - const char *ThisTokBuf = &TokenBuf[0]; - // Get the spelling of the token, which eliminates trigraphs, etc. We know - // that ThisTokBuf points to a buffer that is big enough for the whole token - // and 'spelled' tokens can only shrink. - unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf); - const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote. - - // TODO: Input character set mapping support. - - // Skip L marker for wide strings. - bool ThisIsWide = false; - if (ThisTokBuf[0] == 'L') { - ++ThisTokBuf; - ThisIsWide = true; - } - - assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?"); - ++ThisTokBuf; - - // Check if this is a pascal string - if (pp.getLangOptions().PascalStrings && ThisTokBuf + 1 != ThisTokEnd && - ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') { - - // If the \p sequence is found in the first token, we have a pascal string - // Otherwise, if we already have a pascal string, ignore the first \p - if (i == 0) { - ++ThisTokBuf; - Pascal = true; - } else if (Pascal) - ThisTokBuf += 2; - } - - while (ThisTokBuf != ThisTokEnd) { - // Is this a span of non-escape characters? - if (ThisTokBuf[0] != '\\') { - const char *InStart = ThisTokBuf; - do { - ++ThisTokBuf; - } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\'); - - // Copy the character span over. - unsigned Len = ThisTokBuf-InStart; - if (!AnyWide) { - memcpy(ResultPtr, InStart, Len); - ResultPtr += Len; - } else { - // Note: our internal rep of wide char tokens is always little-endian. - for (; Len; --Len, ++InStart) { - *ResultPtr++ = InStart[0]; - // Add zeros at the end. - for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) - *ResultPtr++ = 0; - } - } - continue; - } - - // Otherwise, this is an escape character. Process it. - unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError, - StringToks[i].getLocation(), - ThisIsWide, PP); - - // Note: our internal rep of wide char tokens is always little-endian. - *ResultPtr++ = ResultChar & 0xFF; - - if (AnyWide) { - for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) - *ResultPtr++ = ResultChar >> i*8; - } - } - } - - // Add zero terminator. - *ResultPtr = 0; - if (AnyWide) { - for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) - *ResultPtr++ = 0; - } - - if (Pascal) - ResultBuf[0] = ResultPtr-&ResultBuf[0]-1; -} diff --git a/clang/Lex/MacroArgs.cpp b/clang/Lex/MacroArgs.cpp deleted file mode 100644 index a26e50eb762..00000000000 --- a/clang/Lex/MacroArgs.cpp +++ /dev/null @@ -1,225 +0,0 @@ -//===--- TokenLexer.cpp - Lex from a token stream -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the TokenLexer interface. -// -//===----------------------------------------------------------------------===// - -#include "MacroArgs.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/Diagnostic.h" -using namespace clang; - -/// MacroArgs ctor function - This destroys the vector passed in. -MacroArgs *MacroArgs::create(const MacroInfo *MI, - const Token *UnexpArgTokens, - unsigned NumToks, bool VarargsElided) { - assert(MI->isFunctionLike() && - "Can't have args for an object-like macro!"); - - // Allocate memory for the MacroArgs object with the lexer tokens at the end. - MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) + - NumToks*sizeof(Token)); - // Construct the macroargs object. - new (Result) MacroArgs(NumToks, VarargsElided); - - // Copy the actual unexpanded tokens to immediately after the result ptr. - if (NumToks) - memcpy(const_cast(Result->getUnexpArgument(0)), - UnexpArgTokens, NumToks*sizeof(Token)); - - return Result; -} - -/// destroy - Destroy and deallocate the memory for this object. -/// -void MacroArgs::destroy() { - // Run the dtor to deallocate the vectors. - this->~MacroArgs(); - // Release the memory for the object. - free(this); -} - - -/// getArgLength - Given a pointer to an expanded or unexpanded argument, -/// return the number of tokens, not counting the EOF, that make up the -/// argument. -unsigned MacroArgs::getArgLength(const Token *ArgPtr) { - unsigned NumArgTokens = 0; - for (; ArgPtr->isNot(tok::eof); ++ArgPtr) - ++NumArgTokens; - return NumArgTokens; -} - - -/// getUnexpArgument - Return the unexpanded tokens for the specified formal. -/// -const Token *MacroArgs::getUnexpArgument(unsigned Arg) const { - // The unexpanded argument tokens start immediately after the MacroArgs object - // in memory. - const Token *Start = (const Token *)(this+1); - const Token *Result = Start; - // Scan to find Arg. - for (; Arg; ++Result) { - assert(Result < Start+NumUnexpArgTokens && "Invalid arg #"); - if (Result->is(tok::eof)) - --Arg; - } - return Result; -} - - -/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected -/// by pre-expansion, return false. Otherwise, conservatively return true. -bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok, - Preprocessor &PP) const { - // If there are no identifiers in the argument list, or if the identifiers are - // known to not be macros, pre-expansion won't modify it. - for (; ArgTok->isNot(tok::eof); ++ArgTok) - if (IdentifierInfo *II = ArgTok->getIdentifierInfo()) { - if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled()) - // Return true even though the macro could be a function-like macro - // without a following '(' token. - return true; - } - return false; -} - -/// getPreExpArgument - Return the pre-expanded form of the specified -/// argument. -const std::vector & -MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) { - assert(Arg < NumUnexpArgTokens && "Invalid argument number!"); - - // If we have already computed this, return it. - if (PreExpArgTokens.empty()) - PreExpArgTokens.resize(NumUnexpArgTokens); - - std::vector &Result = PreExpArgTokens[Arg]; - if (!Result.empty()) return Result; - - const Token *AT = getUnexpArgument(Arg); - unsigned NumToks = getArgLength(AT)+1; // Include the EOF. - - // Otherwise, we have to pre-expand this argument, populating Result. To do - // this, we set up a fake TokenLexer to lex from the unexpanded argument - // list. With this installed, we lex expanded tokens until we hit the EOF - // token at the end of the unexp list. - PP.EnterTokenStream(AT, NumToks, false /*disable expand*/, - false /*owns tokens*/); - - // Lex all of the macro-expanded tokens into Result. - do { - Result.push_back(Token()); - PP.Lex(Result.back()); - } while (Result.back().isNot(tok::eof)); - - // Pop the token stream off the top of the stack. We know that the internal - // pointer inside of it is to the "end" of the token stream, but the stack - // will not otherwise be popped until the next token is lexed. The problem is - // that the token may be lexed sometime after the vector of tokens itself is - // destroyed, which would be badness. - PP.RemoveTopOfLexerStack(); - return Result; -} - - -/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of -/// tokens into the literal string token that should be produced by the C # -/// preprocessor operator. If Charify is true, then it should be turned into -/// a character literal for the Microsoft charize (#@) extension. -/// -Token MacroArgs::StringifyArgument(const Token *ArgToks, - Preprocessor &PP, bool Charify) { - Token Tok; - Tok.startToken(); - Tok.setKind(tok::string_literal); - - const Token *ArgTokStart = ArgToks; - - // Stringify all the tokens. - std::string Result = "\""; - // FIXME: Optimize this loop to not use std::strings. - bool isFirst = true; - for (; ArgToks->isNot(tok::eof); ++ArgToks) { - const Token &Tok = *ArgToks; - if (!isFirst && (Tok.hasLeadingSpace() || Tok.isAtStartOfLine())) - Result += ' '; - isFirst = false; - - // If this is a string or character constant, escape the token as specified - // by 6.10.3.2p2. - if (Tok.is(tok::string_literal) || // "foo" - Tok.is(tok::wide_string_literal) || // L"foo" - Tok.is(tok::char_constant)) { // 'x' and L'x'. - Result += Lexer::Stringify(PP.getSpelling(Tok)); - } else { - // Otherwise, just append the token. - Result += PP.getSpelling(Tok); - } - } - - // If the last character of the string is a \, and if it isn't escaped, this - // is an invalid string literal, diagnose it as specified in C99. - if (Result[Result.size()-1] == '\\') { - // Count the number of consequtive \ characters. If even, then they are - // just escaped backslashes, otherwise it's an error. - unsigned FirstNonSlash = Result.size()-2; - // Guaranteed to find the starting " if nothing else. - while (Result[FirstNonSlash] == '\\') - --FirstNonSlash; - if ((Result.size()-1-FirstNonSlash) & 1) { - // Diagnose errors for things like: #define F(X) #X / F(\) - PP.Diag(ArgToks[-1], diag::pp_invalid_string_literal); - Result.erase(Result.end()-1); // remove one of the \'s. - } - } - Result += '"'; - - // If this is the charify operation and the result is not a legal character - // constant, diagnose it. - if (Charify) { - // First step, turn double quotes into single quotes: - Result[0] = '\''; - Result[Result.size()-1] = '\''; - - // Check for bogus character. - bool isBad = false; - if (Result.size() == 3) { - isBad = Result[1] == '\''; // ''' is not legal. '\' already fixed above. - } else { - isBad = (Result.size() != 4 || Result[1] != '\\'); // Not '\x' - } - - if (isBad) { - PP.Diag(ArgTokStart[0], diag::err_invalid_character_to_charify); - Result = "' '"; // Use something arbitrary, but legal. - } - } - - Tok.setLength(Result.size()); - Tok.setLocation(PP.CreateString(&Result[0], Result.size())); - return Tok; -} - -/// getStringifiedArgument - Compute, cache, and return the specified argument -/// that has been 'stringified' as required by the # operator. -const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, - Preprocessor &PP) { - assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!"); - if (StringifiedArgs.empty()) { - StringifiedArgs.resize(getNumArguments()); - memset(&StringifiedArgs[0], 0, - sizeof(StringifiedArgs[0])*getNumArguments()); - } - if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) - StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP); - return StringifiedArgs[ArgNo]; -} diff --git a/clang/Lex/MacroArgs.h b/clang/Lex/MacroArgs.h deleted file mode 100644 index 4b22fa18aa8..00000000000 --- a/clang/Lex/MacroArgs.h +++ /dev/null @@ -1,109 +0,0 @@ -//===--- MacroArgs.h - Formal argument info for Macros ----------*- 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 MacroArgs interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_MACROARGS_H -#define LLVM_CLANG_MACROARGS_H - -#include - -namespace clang { - class MacroInfo; - class Preprocessor; - class Token; - -/// MacroArgs - An instance of this class captures information about -/// the formal arguments specified to a function-like macro invocation. -class MacroArgs { - /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the - /// arguments. All of the actual argument tokens are allocated immediately - /// after the MacroArgs object in memory. This is all of the arguments - /// concatenated together, with 'EOF' markers at the end of each argument. - unsigned NumUnexpArgTokens; - - /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty - /// if not yet computed. This includes the EOF marker at the end of the - /// stream. - std::vector > PreExpArgTokens; - - /// StringifiedArgs - This contains arguments in 'stringified' form. If the - /// stringified form of an argument has not yet been computed, this is empty. - std::vector StringifiedArgs; - - /// VarargsElided - True if this is a C99 style varargs macro invocation and - /// there was no argument specified for the "..." argument. If the argument - /// was specified (even empty) or this isn't a C99 style varargs function, or - /// if in strict mode and the C99 varargs macro had only a ... argument, this - /// is false. - bool VarargsElided; - - MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {} - ~MacroArgs() {} -public: - /// MacroArgs ctor function - Create a new MacroArgs object with the specified - /// macro and argument info. - static MacroArgs *create(const MacroInfo *MI, - const Token *UnexpArgTokens, - unsigned NumArgTokens, bool VarargsElided); - - /// destroy - Destroy and deallocate the memory for this object. - /// - void destroy(); - - /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected - /// by pre-expansion, return false. Otherwise, conservatively return true. - bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const; - - /// getUnexpArgument - Return a pointer to the first token of the unexpanded - /// token list for the specified formal. - /// - const Token *getUnexpArgument(unsigned Arg) const; - - /// getArgLength - Given a pointer to an expanded or unexpanded argument, - /// return the number of tokens, not counting the EOF, that make up the - /// argument. - static unsigned getArgLength(const Token *ArgPtr); - - /// getPreExpArgument - Return the pre-expanded form of the specified - /// argument. - const std::vector & - getPreExpArgument(unsigned Arg, Preprocessor &PP); - - /// getStringifiedArgument - Compute, cache, and return the specified argument - /// that has been 'stringified' as required by the # operator. - const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP); - - /// getNumArguments - Return the number of arguments passed into this macro - /// invocation. - unsigned getNumArguments() const { return NumUnexpArgTokens; } - - - /// isVarargsElidedUse - Return true if this is a C99 style varargs macro - /// invocation and there was no argument specified for the "..." argument. If - /// the argument was specified (even empty) or this isn't a C99 style varargs - /// function, or if in strict mode and the C99 varargs macro had only a ... - /// argument, this returns false. - bool isVarargsElidedUse() const { return VarargsElided; } - - /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of - /// tokens into the literal string token that should be produced by the C # - /// preprocessor operator. If Charify is true, then it should be turned into - /// a character literal for the Microsoft charize (#@) extension. - /// - static Token StringifyArgument(const Token *ArgToks, - Preprocessor &PP, bool Charify = false); -}; - -} // end namespace clang - -#endif diff --git a/clang/Lex/MacroInfo.cpp b/clang/Lex/MacroInfo.cpp deleted file mode 100644 index de19ff502a6..00000000000 --- a/clang/Lex/MacroInfo.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===--- MacroInfo.cpp - Information about #defined identifiers -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the MacroInfo interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/Preprocessor.h" -using namespace clang; - -MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { - IsFunctionLike = false; - IsC99Varargs = false; - IsGNUVarargs = false; - IsBuiltinMacro = false; - IsDisabled = false; - IsUsed = true; - - ArgumentList = 0; - NumArguments = 0; -} - -/// isIdenticalTo - Return true if the specified macro definition is equal to -/// this macro in spelling, arguments, and whitespace. This is used to emit -/// duplicate definition warnings. This implements the rules in C99 6.10.3. -/// -bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const { - // Check # tokens in replacement, number of args, and various flags all match. - if (ReplacementTokens.size() != Other.ReplacementTokens.size() || - getNumArgs() != Other.getNumArgs() || - isFunctionLike() != Other.isFunctionLike() || - isC99Varargs() != Other.isC99Varargs() || - isGNUVarargs() != Other.isGNUVarargs()) - return false; - - // Check arguments. - for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end(); - I != E; ++I, ++OI) - if (*I != *OI) return false; - - // Check all the tokens. - for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) { - const Token &A = ReplacementTokens[i]; - const Token &B = Other.ReplacementTokens[i]; - if (A.getKind() != B.getKind() || - A.isAtStartOfLine() != B.isAtStartOfLine() || - A.hasLeadingSpace() != B.hasLeadingSpace()) - return false; - - // If this is an identifier, it is easy. - if (A.getIdentifierInfo() || B.getIdentifierInfo()) { - if (A.getIdentifierInfo() != B.getIdentifierInfo()) - return false; - continue; - } - - // Otherwise, check the spelling. - if (PP.getSpelling(A) != PP.getSpelling(B)) - return false; - } - - return true; -} diff --git a/clang/Lex/Makefile b/clang/Lex/Makefile deleted file mode 100644 index 3c67f088015..00000000000 --- a/clang/Lex/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -##===- clang/Lex/Makefile ----------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the Lexer library for the C-Language front-end. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -include $(LEVEL)/Makefile.config - -LIBRARYNAME := clangLex -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -ifeq ($(ARCH),PowerPC) -CXXFLAGS += -maltivec -endif - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/Lex/PPDirectives.cpp b/clang/Lex/PPDirectives.cpp deleted file mode 100644 index b24f5b63760..00000000000 --- a/clang/Lex/PPDirectives.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -//===--- PPDirectives.cpp - Directive Handling for Preprocessor -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements # directive processing for the Preprocessor. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Utility Methods for Preprocessor Directive Handling. -//===----------------------------------------------------------------------===// - -/// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the -/// current line until the tok::eom token is found. -void Preprocessor::DiscardUntilEndOfDirective() { - Token Tmp; - do { - LexUnexpandedToken(Tmp); - } while (Tmp.isNot(tok::eom)); -} - -/// isCXXNamedOperator - Returns "true" if the token is a named operator in C++. -static bool isCXXNamedOperator(const std::string &Spelling) { - return Spelling == "and" || Spelling == "bitand" || Spelling == "bitor" || - Spelling == "compl" || Spelling == "not" || Spelling == "not_eq" || - Spelling == "or" || Spelling == "xor"; -} - -/// ReadMacroName - Lex and validate a macro name, which occurs after a -/// #define or #undef. This sets the token kind to eom and discards the rest -/// of the macro line if the macro name is invalid. isDefineUndef is 1 if -/// this is due to a a #define, 2 if #undef directive, 0 if it is something -/// else (e.g. #ifdef). -void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { - // Read the token, don't allow macro expansion on it. - LexUnexpandedToken(MacroNameTok); - - // Missing macro name? - if (MacroNameTok.is(tok::eom)) - return Diag(MacroNameTok, diag::err_pp_missing_macro_name); - - IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); - if (II == 0) { - std::string Spelling = getSpelling(MacroNameTok); - if (isCXXNamedOperator(Spelling)) - // C++ 2.5p2: Alternative tokens behave the same as its primary token - // except for their spellings. - Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name, Spelling); - else - Diag(MacroNameTok, diag::err_pp_macro_not_identifier); - // Fall through on error. - } else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) { - // Error if defining "defined": C99 6.10.8.4. - Diag(MacroNameTok, diag::err_defined_macro_name); - } else if (isDefineUndef && II->hasMacroDefinition() && - getMacroInfo(II)->isBuiltinMacro()) { - // Error if defining "__LINE__" and other builtins: C99 6.10.8.4. - if (isDefineUndef == 1) - Diag(MacroNameTok, diag::pp_redef_builtin_macro); - else - Diag(MacroNameTok, diag::pp_undef_builtin_macro); - } else { - // Okay, we got a good identifier node. Return it. - return; - } - - // Invalid macro name, read and discard the rest of the line. Then set the - // token kind to tok::eom. - MacroNameTok.setKind(tok::eom); - return DiscardUntilEndOfDirective(); -} - -/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If -/// not, emit a diagnostic and consume up until the eom. -void Preprocessor::CheckEndOfDirective(const char *DirType) { - Token Tmp; - // Lex unexpanded tokens: macros might expand to zero tokens, causing us to - // miss diagnosing invalid lines. - LexUnexpandedToken(Tmp); - - // There should be no tokens after the directive, but we allow them as an - // extension. - while (Tmp.is(tok::comment)) // Skip comments in -C mode. - LexUnexpandedToken(Tmp); - - if (Tmp.isNot(tok::eom)) { - Diag(Tmp, diag::ext_pp_extra_tokens_at_eol, DirType); - DiscardUntilEndOfDirective(); - } -} - - - -/// SkipExcludedConditionalBlock - We just read a #if or related directive and -/// decided that the subsequent tokens are in the #if'd out portion of the -/// file. Lex the rest of the file, until we see an #endif. If -/// FoundNonSkipPortion is true, then we have already emitted code for part of -/// this #if directive, so #else/#elif blocks should never be entered. If ElseOk -/// is true, then #else directives are ok, if not, then we have already seen one -/// so a #else directive is a duplicate. When this returns, the caller can lex -/// the first valid token. -void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, - bool FoundNonSkipPortion, - bool FoundElse) { - ++NumSkipped; - assert(CurTokenLexer == 0 && CurLexer && - "Lexing a macro, not a file?"); - - CurLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false, - FoundNonSkipPortion, FoundElse); - - // Enter raw mode to disable identifier lookup (and thus macro expansion), - // disabling warnings, etc. - CurLexer->LexingRawMode = true; - Token Tok; - while (1) { - CurLexer->Lex(Tok); - - // If this is the end of the buffer, we have an error. - if (Tok.is(tok::eof)) { - // Emit errors for each unterminated conditional on the stack, including - // the current one. - while (!CurLexer->ConditionalStack.empty()) { - Diag(CurLexer->ConditionalStack.back().IfLoc, - diag::err_pp_unterminated_conditional); - CurLexer->ConditionalStack.pop_back(); - } - - // Just return and let the caller lex after this #include. - break; - } - - // If this token is not a preprocessor directive, just skip it. - if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine()) - continue; - - // We just parsed a # character at the start of a line, so we're in - // directive mode. Tell the lexer this so any newlines we see will be - // converted into an EOM token (this terminates the macro). - CurLexer->ParsingPreprocessorDirective = true; - CurLexer->KeepCommentMode = false; - - - // Read the next token, the directive flavor. - LexUnexpandedToken(Tok); - - // If this isn't an identifier directive (e.g. is "# 1\n" or "#\n", or - // something bogus), skip it. - if (Tok.isNot(tok::identifier)) { - CurLexer->ParsingPreprocessorDirective = false; - // Restore comment saving mode. - CurLexer->KeepCommentMode = KeepComments; - continue; - } - - // If the first letter isn't i or e, it isn't intesting to us. We know that - // this is safe in the face of spelling differences, because there is no way - // to spell an i/e in a strange way that is another letter. Skipping this - // allows us to avoid looking up the identifier info for #define/#undef and - // other common directives. - const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation()); - char FirstChar = RawCharData[0]; - if (FirstChar >= 'a' && FirstChar <= 'z' && - FirstChar != 'i' && FirstChar != 'e') { - CurLexer->ParsingPreprocessorDirective = false; - // Restore comment saving mode. - CurLexer->KeepCommentMode = KeepComments; - continue; - } - - // Get the identifier name without trigraphs or embedded newlines. Note - // that we can't use Tok.getIdentifierInfo() because its lookup is disabled - // when skipping. - // TODO: could do this with zero copies in the no-clean case by using - // strncmp below. - char Directive[20]; - unsigned IdLen; - if (!Tok.needsCleaning() && Tok.getLength() < 20) { - IdLen = Tok.getLength(); - memcpy(Directive, RawCharData, IdLen); - Directive[IdLen] = 0; - } else { - std::string DirectiveStr = getSpelling(Tok); - IdLen = DirectiveStr.size(); - if (IdLen >= 20) { - CurLexer->ParsingPreprocessorDirective = false; - // Restore comment saving mode. - CurLexer->KeepCommentMode = KeepComments; - continue; - } - memcpy(Directive, &DirectiveStr[0], IdLen); - Directive[IdLen] = 0; - } - - if (FirstChar == 'i' && Directive[1] == 'f') { - if ((IdLen == 2) || // "if" - (IdLen == 5 && !strcmp(Directive+2, "def")) || // "ifdef" - (IdLen == 6 && !strcmp(Directive+2, "ndef"))) { // "ifndef" - // We know the entire #if/#ifdef/#ifndef block will be skipped, don't - // bother parsing the condition. - DiscardUntilEndOfDirective(); - CurLexer->pushConditionalLevel(Tok.getLocation(), /*wasskipping*/true, - /*foundnonskip*/false, - /*fnddelse*/false); - } - } else if (FirstChar == 'e') { - if (IdLen == 5 && !strcmp(Directive+1, "ndif")) { // "endif" - CheckEndOfDirective("#endif"); - PPConditionalInfo CondInfo; - CondInfo.WasSkipping = true; // Silence bogus warning. - bool InCond = CurLexer->popConditionalLevel(CondInfo); - InCond = InCond; // Silence warning in no-asserts mode. - assert(!InCond && "Can't be skipping if not in a conditional!"); - - // If we popped the outermost skipping block, we're done skipping! - if (!CondInfo.WasSkipping) - break; - } else if (IdLen == 4 && !strcmp(Directive+1, "lse")) { // "else". - // #else directive in a skipping conditional. If not in some other - // skipping conditional, and if #else hasn't already been seen, enter it - // as a non-skipping conditional. - CheckEndOfDirective("#else"); - PPConditionalInfo &CondInfo = CurLexer->peekConditionalLevel(); - - // If this is a #else with a #else before it, report the error. - if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_else_after_else); - - // Note that we've seen a #else in this conditional. - CondInfo.FoundElse = true; - - // If the conditional is at the top level, and the #if block wasn't - // entered, enter the #else block now. - if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) { - CondInfo.FoundNonSkip = true; - break; - } - } else if (IdLen == 4 && !strcmp(Directive+1, "lif")) { // "elif". - PPConditionalInfo &CondInfo = CurLexer->peekConditionalLevel(); - - bool ShouldEnter; - // If this is in a skipping block or if we're already handled this #if - // block, don't bother parsing the condition. - if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) { - DiscardUntilEndOfDirective(); - ShouldEnter = false; - } else { - // Restore the value of LexingRawMode so that identifiers are - // looked up, etc, inside the #elif expression. - assert(CurLexer->LexingRawMode && "We have to be skipping here!"); - CurLexer->LexingRawMode = false; - IdentifierInfo *IfNDefMacro = 0; - ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro); - CurLexer->LexingRawMode = true; - } - - // If this is a #elif with a #else before it, report the error. - if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else); - - // If this condition is true, enter it! - if (ShouldEnter) { - CondInfo.FoundNonSkip = true; - break; - } - } - } - - CurLexer->ParsingPreprocessorDirective = false; - // Restore comment saving mode. - CurLexer->KeepCommentMode = KeepComments; - } - - // Finally, if we are out of the conditional (saw an #endif or ran off the end - // of the file, just stop skipping and return to lexing whatever came after - // the #if block. - CurLexer->LexingRawMode = false; -} - -/// LookupFile - Given a "foo" or reference, look up the indicated file, -/// return null on failure. isAngled indicates whether the file reference is -/// for system #include's or not (i.e. using <> instead of ""). -const FileEntry *Preprocessor::LookupFile(const char *FilenameStart, - const char *FilenameEnd, - bool isAngled, - const DirectoryLookup *FromDir, - const DirectoryLookup *&CurDir) { - // If the header lookup mechanism may be relative to the current file, pass in - // info about where the current file is. - const FileEntry *CurFileEnt = 0; - if (!FromDir) { - SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc(); - CurFileEnt = SourceMgr.getFileEntryForLoc(FileLoc); - } - - // Do a standard file entry lookup. - CurDir = CurDirLookup; - const FileEntry *FE = - HeaderInfo.LookupFile(FilenameStart, FilenameEnd, - isAngled, FromDir, CurDir, CurFileEnt); - if (FE) return FE; - - // Otherwise, see if this is a subframework header. If so, this is relative - // to one of the headers on the #include stack. Walk the list of the current - // headers on the #include stack and pass them to HeaderInfo. - if (CurLexer && !CurLexer->Is_PragmaLexer) { - if ((CurFileEnt = SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc()))) - if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, FilenameEnd, - CurFileEnt))) - return FE; - } - - for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) { - IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1]; - if (ISEntry.TheLexer && !ISEntry.TheLexer->Is_PragmaLexer) { - if ((CurFileEnt = - SourceMgr.getFileEntryForLoc(ISEntry.TheLexer->getFileLoc()))) - if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, - FilenameEnd, CurFileEnt))) - return FE; - } - } - - // Otherwise, we really couldn't find the file. - return 0; -} - - -//===----------------------------------------------------------------------===// -// Preprocessor Directive Handling. -//===----------------------------------------------------------------------===// - -/// HandleDirective - This callback is invoked when the lexer sees a # token -/// at the start of a line. This consumes the directive, modifies the -/// lexer/preprocessor state, and advances the lexer(s) so that the next token -/// read is the correct one. -void Preprocessor::HandleDirective(Token &Result) { - // FIXME: Traditional: # with whitespace before it not recognized by K&R? - - // We just parsed a # character at the start of a line, so we're in directive - // mode. Tell the lexer this so any newlines we see will be converted into an - // EOM token (which terminates the directive). - CurLexer->ParsingPreprocessorDirective = true; - - ++NumDirectives; - - // We are about to read a token. For the multiple-include optimization FA to - // work, we have to remember if we had read any tokens *before* this - // pp-directive. - bool ReadAnyTokensBeforeDirective = CurLexer->MIOpt.getHasReadAnyTokensVal(); - - // Read the next token, the directive flavor. This isn't expanded due to - // C99 6.10.3p8. - LexUnexpandedToken(Result); - - // C99 6.10.3p11: Is this preprocessor directive in macro invocation? e.g.: - // #define A(x) #x - // A(abc - // #warning blah - // def) - // If so, the user is relying on non-portable behavior, emit a diagnostic. - if (InMacroArgs) - Diag(Result, diag::ext_embedded_directive); - -TryAgain: - switch (Result.getKind()) { - case tok::eom: - return; // null directive. - case tok::comment: - // Handle stuff like "# /*foo*/ define X" in -E -C mode. - LexUnexpandedToken(Result); - goto TryAgain; - - case tok::numeric_constant: - // FIXME: implement # 7 line numbers! - DiscardUntilEndOfDirective(); - return; - default: - IdentifierInfo *II = Result.getIdentifierInfo(); - if (II == 0) break; // Not an identifier. - - // Ask what the preprocessor keyword ID is. - switch (II->getPPKeywordID()) { - default: break; - // C99 6.10.1 - Conditional Inclusion. - case tok::pp_if: - return HandleIfDirective(Result, ReadAnyTokensBeforeDirective); - case tok::pp_ifdef: - return HandleIfdefDirective(Result, false, true/*not valid for miopt*/); - case tok::pp_ifndef: - return HandleIfdefDirective(Result, true, ReadAnyTokensBeforeDirective); - case tok::pp_elif: - return HandleElifDirective(Result); - case tok::pp_else: - return HandleElseDirective(Result); - case tok::pp_endif: - return HandleEndifDirective(Result); - - // C99 6.10.2 - Source File Inclusion. - case tok::pp_include: - return HandleIncludeDirective(Result); // Handle #include. - - // C99 6.10.3 - Macro Replacement. - case tok::pp_define: - return HandleDefineDirective(Result); - case tok::pp_undef: - return HandleUndefDirective(Result); - - // C99 6.10.4 - Line Control. - case tok::pp_line: - // FIXME: implement #line - DiscardUntilEndOfDirective(); - return; - - // C99 6.10.5 - Error Directive. - case tok::pp_error: - return HandleUserDiagnosticDirective(Result, false); - - // C99 6.10.6 - Pragma Directive. - case tok::pp_pragma: - return HandlePragmaDirective(); - - // GNU Extensions. - case tok::pp_import: - return HandleImportDirective(Result); - case tok::pp_include_next: - return HandleIncludeNextDirective(Result); - - case tok::pp_warning: - Diag(Result, diag::ext_pp_warning_directive); - return HandleUserDiagnosticDirective(Result, true); - case tok::pp_ident: - return HandleIdentSCCSDirective(Result); - case tok::pp_sccs: - return HandleIdentSCCSDirective(Result); - case tok::pp_assert: - //isExtension = true; // FIXME: implement #assert - break; - case tok::pp_unassert: - //isExtension = true; // FIXME: implement #unassert - break; - } - break; - } - - // If we reached here, the preprocessing token is not valid! - Diag(Result, diag::err_pp_invalid_directive); - - // Read the rest of the PP line. - DiscardUntilEndOfDirective(); - - // Okay, we're done parsing the directive. -} - -void Preprocessor::HandleUserDiagnosticDirective(Token &Tok, - bool isWarning) { - // Read the rest of the line raw. We do this because we don't want macros - // to be expanded and we don't require that the tokens be valid preprocessing - // tokens. For example, this is allowed: "#warning ` 'foo". GCC does - // collapse multiple consequtive white space between tokens, but this isn't - // specified by the standard. - std::string Message = CurLexer->ReadToEndOfLine(); - - unsigned DiagID = isWarning ? diag::pp_hash_warning : diag::err_pp_hash_error; - return Diag(Tok, DiagID, Message); -} - -/// HandleIdentSCCSDirective - Handle a #ident/#sccs directive. -/// -void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { - // Yes, this directive is an extension. - Diag(Tok, diag::ext_pp_ident_directive); - - // Read the string argument. - Token StrTok; - Lex(StrTok); - - // If the token kind isn't a string, it's a malformed directive. - if (StrTok.isNot(tok::string_literal) && - StrTok.isNot(tok::wide_string_literal)) - return Diag(StrTok, diag::err_pp_malformed_ident); - - // Verify that there is nothing after the string, other than EOM. - CheckEndOfDirective("#ident"); - - if (Callbacks) - Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok)); -} - -//===----------------------------------------------------------------------===// -// Preprocessor Include Directive Handling. -//===----------------------------------------------------------------------===// - -/// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully -/// checked and spelled filename, e.g. as an operand of #include. This returns -/// true if the input filename was in <>'s or false if it were in ""'s. The -/// caller is expected to provide a buffer that is large enough to hold the -/// spelling of the filename, but is also expected to handle the case when -/// this method decides to use a different buffer. -bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, - const char *&BufStart, - const char *&BufEnd) { - // Get the text form of the filename. - assert(BufStart != BufEnd && "Can't have tokens with empty spellings!"); - - // Make sure the filename is or "x". - bool isAngled; - if (BufStart[0] == '<') { - if (BufEnd[-1] != '>') { - Diag(Loc, diag::err_pp_expects_filename); - BufStart = 0; - return true; - } - isAngled = true; - } else if (BufStart[0] == '"') { - if (BufEnd[-1] != '"') { - Diag(Loc, diag::err_pp_expects_filename); - BufStart = 0; - return true; - } - isAngled = false; - } else { - Diag(Loc, diag::err_pp_expects_filename); - BufStart = 0; - return true; - } - - // Diagnose #include "" as invalid. - if (BufEnd-BufStart <= 2) { - Diag(Loc, diag::err_pp_empty_filename); - BufStart = 0; - return ""; - } - - // Skip the brackets. - ++BufStart; - --BufEnd; - return isAngled; -} - -/// ConcatenateIncludeName - Handle cases where the #include name is expanded -/// from a macro as multiple tokens, which need to be glued together. This -/// occurs for code like: -/// #define FOO -/// #include FOO -/// because in this case, "" is returned as 7 tokens, not one. -/// -/// This code concatenates and consumes tokens up to the '>' token. It returns -/// false if the > was found, otherwise it returns true if it finds and consumes -/// the EOM marker. -static bool ConcatenateIncludeName(llvm::SmallVector &FilenameBuffer, - Preprocessor &PP) { - Token CurTok; - - PP.Lex(CurTok); - while (CurTok.isNot(tok::eom)) { - // Append the spelling of this token to the buffer. If there was a space - // before it, add it now. - if (CurTok.hasLeadingSpace()) - FilenameBuffer.push_back(' '); - - // Get the spelling of the token, directly into FilenameBuffer if possible. - unsigned PreAppendSize = FilenameBuffer.size(); - FilenameBuffer.resize(PreAppendSize+CurTok.getLength()); - - const char *BufPtr = &FilenameBuffer[PreAppendSize]; - unsigned ActualLen = PP.getSpelling(CurTok, BufPtr); - - // If the token was spelled somewhere else, copy it into FilenameBuffer. - if (BufPtr != &FilenameBuffer[PreAppendSize]) - memcpy(&FilenameBuffer[PreAppendSize], BufPtr, ActualLen); - - // Resize FilenameBuffer to the correct size. - if (CurTok.getLength() != ActualLen) - FilenameBuffer.resize(PreAppendSize+ActualLen); - - // If we found the '>' marker, return success. - if (CurTok.is(tok::greater)) - return false; - - PP.Lex(CurTok); - } - - // If we hit the eom marker, emit an error and return true so that the caller - // knows the EOM has been read. - PP.Diag(CurTok.getLocation(), diag::err_pp_expects_filename); - return true; -} - -/// HandleIncludeDirective - The "#include" tokens have just been read, read the -/// file to be included from the lexer, then include it! This is a common -/// routine with functionality shared between #include, #include_next and -/// #import. -void Preprocessor::HandleIncludeDirective(Token &IncludeTok, - const DirectoryLookup *LookupFrom, - bool isImport) { - - Token FilenameTok; - CurLexer->LexIncludeFilename(FilenameTok); - - // Reserve a buffer to get the spelling. - llvm::SmallVector FilenameBuffer; - const char *FilenameStart, *FilenameEnd; - - switch (FilenameTok.getKind()) { - case tok::eom: - // If the token kind is EOM, the error has already been diagnosed. - return; - - case tok::angle_string_literal: - case tok::string_literal: { - FilenameBuffer.resize(FilenameTok.getLength()); - FilenameStart = &FilenameBuffer[0]; - unsigned Len = getSpelling(FilenameTok, FilenameStart); - FilenameEnd = FilenameStart+Len; - break; - } - - case tok::less: - // This could be a file coming from a macro expansion. In this - // case, glue the tokens together into FilenameBuffer and interpret those. - FilenameBuffer.push_back('<'); - if (ConcatenateIncludeName(FilenameBuffer, *this)) - return; // Found but no ">"? Diagnostic already emitted. - FilenameStart = &FilenameBuffer[0]; - FilenameEnd = &FilenameBuffer[FilenameBuffer.size()]; - break; - default: - Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); - DiscardUntilEndOfDirective(); - return; - } - - bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), - FilenameStart, FilenameEnd); - // If GetIncludeFilenameSpelling set the start ptr to null, there was an - // error. - if (FilenameStart == 0) { - DiscardUntilEndOfDirective(); - return; - } - - // Verify that there is nothing after the filename, other than EOM. Use the - // preprocessor to lex this in case lexing the filename entered a macro. - CheckEndOfDirective("#include"); - - // Check that we don't have infinite #include recursion. - if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) - return Diag(FilenameTok, diag::err_pp_include_too_deep); - - // Search include directories. - const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(FilenameStart, FilenameEnd, - isAngled, LookupFrom, CurDir); - if (File == 0) - return Diag(FilenameTok, diag::err_pp_file_not_found, - std::string(FilenameStart, FilenameEnd)); - - // Ask HeaderInfo if we should enter this #include file. - if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) { - // If it returns true, #including this file will have no effect. - return; - } - - // Look up the file, create a File ID for it. - unsigned FileID = SourceMgr.createFileID(File, FilenameTok.getLocation()); - if (FileID == 0) - return Diag(FilenameTok, diag::err_pp_file_not_found, - std::string(FilenameStart, FilenameEnd)); - - // Finally, if all is good, enter the new file! - EnterSourceFile(FileID, CurDir); -} - -/// HandleIncludeNextDirective - Implements #include_next. -/// -void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) { - Diag(IncludeNextTok, diag::ext_pp_include_next_directive); - - // #include_next is like #include, except that we start searching after - // the current found directory. If we can't do this, issue a - // diagnostic. - const DirectoryLookup *Lookup = CurDirLookup; - if (isInPrimaryFile()) { - Lookup = 0; - Diag(IncludeNextTok, diag::pp_include_next_in_primary); - } else if (Lookup == 0) { - Diag(IncludeNextTok, diag::pp_include_next_absolute_path); - } else { - // Start looking up in the next directory. - ++Lookup; - } - - return HandleIncludeDirective(IncludeNextTok, Lookup); -} - -/// HandleImportDirective - Implements #import. -/// -void Preprocessor::HandleImportDirective(Token &ImportTok) { - Diag(ImportTok, diag::ext_pp_import_directive); - - return HandleIncludeDirective(ImportTok, 0, true); -} - -//===----------------------------------------------------------------------===// -// Preprocessor Macro Directive Handling. -//===----------------------------------------------------------------------===// - -/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro -/// definition has just been read. Lex the rest of the arguments and the -/// closing ), updating MI with what we learn. Return true if an error occurs -/// parsing the arg list. -bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) { - llvm::SmallVector Arguments; - - Token Tok; - while (1) { - LexUnexpandedToken(Tok); - switch (Tok.getKind()) { - case tok::r_paren: - // Found the end of the argument list. - if (Arguments.empty()) { // #define FOO() - MI->setArgumentList(Arguments.begin(), Arguments.end()); - return false; - } - // Otherwise we have #define FOO(A,) - Diag(Tok, diag::err_pp_expected_ident_in_arg_list); - return true; - case tok::ellipsis: // #define X(... -> C99 varargs - // Warn if use of C99 feature in non-C99 mode. - if (!Features.C99) Diag(Tok, diag::ext_variadic_macro); - - // Lex the token after the identifier. - LexUnexpandedToken(Tok); - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); - return true; - } - // Add the __VA_ARGS__ identifier as an argument. - Arguments.push_back(Ident__VA_ARGS__); - MI->setIsC99Varargs(); - MI->setArgumentList(Arguments.begin(), Arguments.end()); - return false; - case tok::eom: // #define X( - Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); - return true; - default: - // Handle keywords and identifiers here to accept things like - // #define Foo(for) for. - IdentifierInfo *II = Tok.getIdentifierInfo(); - if (II == 0) { - // #define X(1 - Diag(Tok, diag::err_pp_invalid_tok_in_arg_list); - return true; - } - - // If this is already used as an argument, it is used multiple times (e.g. - // #define X(A,A. - if (std::find(Arguments.begin(), Arguments.end(), II) != - Arguments.end()) { // C99 6.10.3p6 - Diag(Tok, diag::err_pp_duplicate_name_in_arg_list, II->getName()); - return true; - } - - // Add the argument to the macro info. - Arguments.push_back(II); - - // Lex the token after the identifier. - LexUnexpandedToken(Tok); - - switch (Tok.getKind()) { - default: // #define X(A B - Diag(Tok, diag::err_pp_expected_comma_in_arg_list); - return true; - case tok::r_paren: // #define X(A) - MI->setArgumentList(Arguments.begin(), Arguments.end()); - return false; - case tok::comma: // #define X(A, - break; - case tok::ellipsis: // #define X(A... -> GCC extension - // Diagnose extension. - Diag(Tok, diag::ext_named_variadic_macro); - - // Lex the token after the identifier. - LexUnexpandedToken(Tok); - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); - return true; - } - - MI->setIsGNUVarargs(); - MI->setArgumentList(Arguments.begin(), Arguments.end()); - return false; - } - } - } -} - -/// HandleDefineDirective - Implements #define. This consumes the entire macro -/// line then lets the caller lex the next real token. -void Preprocessor::HandleDefineDirective(Token &DefineTok) { - ++NumDefined; - - Token MacroNameTok; - ReadMacroName(MacroNameTok, 1); - - // Error reading macro name? If so, diagnostic already issued. - if (MacroNameTok.is(tok::eom)) - return; - - // If we are supposed to keep comments in #defines, reenable comment saving - // mode. - CurLexer->KeepCommentMode = KeepMacroComments; - - // Create the new macro. - MacroInfo *MI = new MacroInfo(MacroNameTok.getLocation()); - - Token Tok; - LexUnexpandedToken(Tok); - - // If this is a function-like macro definition, parse the argument list, - // marking each of the identifiers as being used as macro arguments. Also, - // check other constraints on the first token of the macro body. - if (Tok.is(tok::eom)) { - // If there is no body to this macro, we have no special handling here. - } else if (Tok.is(tok::l_paren) && !Tok.hasLeadingSpace()) { - // This is a function-like macro definition. Read the argument list. - MI->setIsFunctionLike(); - if (ReadMacroDefinitionArgList(MI)) { - // Forget about MI. - delete MI; - // Throw away the rest of the line. - if (CurLexer->ParsingPreprocessorDirective) - DiscardUntilEndOfDirective(); - return; - } - - // Read the first token after the arg list for down below. - LexUnexpandedToken(Tok); - } else if (!Tok.hasLeadingSpace()) { - // C99 requires whitespace between the macro definition and the body. Emit - // a diagnostic for something like "#define X+". - if (Features.C99) { - Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name); - } else { - // FIXME: C90/C++ do not get this diagnostic, but it does get a similar - // one in some cases! - } - } else { - // This is a normal token with leading space. Clear the leading space - // marker on the first token to get proper expansion. - Tok.clearFlag(Token::LeadingSpace); - } - - // If this is a definition of a variadic C99 function-like macro, not using - // the GNU named varargs extension, enabled __VA_ARGS__. - - // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. - // This gets unpoisoned where it is allowed. - assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!"); - if (MI->isC99Varargs()) - Ident__VA_ARGS__->setIsPoisoned(false); - - // Read the rest of the macro body. - if (MI->isObjectLike()) { - // Object-like macros are very simple, just read their body. - while (Tok.isNot(tok::eom)) { - MI->AddTokenToBody(Tok); - // Get the next token of the macro. - LexUnexpandedToken(Tok); - } - - } else { - // Otherwise, read the body of a function-like macro. This has to validate - // the # (stringize) operator. - while (Tok.isNot(tok::eom)) { - MI->AddTokenToBody(Tok); - - // Check C99 6.10.3.2p1: ensure that # operators are followed by macro - // parameters in function-like macro expansions. - if (Tok.isNot(tok::hash)) { - // Get the next token of the macro. - LexUnexpandedToken(Tok); - continue; - } - - // Get the next token of the macro. - LexUnexpandedToken(Tok); - - // Not a macro arg identifier? - if (!Tok.getIdentifierInfo() || - MI->getArgumentNum(Tok.getIdentifierInfo()) == -1) { - Diag(Tok, diag::err_pp_stringize_not_parameter); - delete MI; - - // Disable __VA_ARGS__ again. - Ident__VA_ARGS__->setIsPoisoned(true); - return; - } - - // Things look ok, add the param name token to the macro. - MI->AddTokenToBody(Tok); - - // Get the next token of the macro. - LexUnexpandedToken(Tok); - } - } - - - // Disable __VA_ARGS__ again. - Ident__VA_ARGS__->setIsPoisoned(true); - - // Check that there is no paste (##) operator at the begining or end of the - // replacement list. - unsigned NumTokens = MI->getNumTokens(); - if (NumTokens != 0) { - if (MI->getReplacementToken(0).is(tok::hashhash)) { - Diag(MI->getReplacementToken(0), diag::err_paste_at_start); - delete MI; - return; - } - if (MI->getReplacementToken(NumTokens-1).is(tok::hashhash)) { - Diag(MI->getReplacementToken(NumTokens-1), diag::err_paste_at_end); - delete MI; - return; - } - } - - // If this is the primary source file, remember that this macro hasn't been - // used yet. - if (isInPrimaryFile()) - MI->setIsUsed(false); - - // Finally, if this identifier already had a macro defined for it, verify that - // the macro bodies are identical and free the old definition. - if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) { - if (!OtherMI->isUsed()) - Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used); - - // Macros must be identical. This means all tokes and whitespace separation - // must be the same. C99 6.10.3.2. - if (!MI->isIdenticalTo(*OtherMI, *this)) { - Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef, - MacroNameTok.getIdentifierInfo()->getName()); - Diag(OtherMI->getDefinitionLoc(), diag::ext_pp_macro_redef2); - } - delete OtherMI; - } - - setMacroInfo(MacroNameTok.getIdentifierInfo(), MI); -} - -/// HandleUndefDirective - Implements #undef. -/// -void Preprocessor::HandleUndefDirective(Token &UndefTok) { - ++NumUndefined; - - Token MacroNameTok; - ReadMacroName(MacroNameTok, 2); - - // Error reading macro name? If so, diagnostic already issued. - if (MacroNameTok.is(tok::eom)) - return; - - // Check to see if this is the last token on the #undef line. - CheckEndOfDirective("#undef"); - - // Okay, we finally have a valid identifier to undef. - MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo()); - - // If the macro is not defined, this is a noop undef, just return. - if (MI == 0) return; - - if (!MI->isUsed()) - Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); - - // Free macro definition. - delete MI; - setMacroInfo(MacroNameTok.getIdentifierInfo(), 0); -} - - -//===----------------------------------------------------------------------===// -// Preprocessor Conditional Directive Handling. -//===----------------------------------------------------------------------===// - -/// HandleIfdefDirective - Implements the #ifdef/#ifndef directive. isIfndef is -/// true when this is a #ifndef directive. ReadAnyTokensBeforeDirective is true -/// if any tokens have been returned or pp-directives activated before this -/// #ifndef has been lexed. -/// -void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, - bool ReadAnyTokensBeforeDirective) { - ++NumIf; - Token DirectiveTok = Result; - - Token MacroNameTok; - ReadMacroName(MacroNameTok); - - // Error reading macro name? If so, diagnostic already issued. - if (MacroNameTok.is(tok::eom)) { - // Skip code until we get to #endif. This helps with recovery by not - // emitting an error when the #endif is reached. - SkipExcludedConditionalBlock(DirectiveTok.getLocation(), - /*Foundnonskip*/false, /*FoundElse*/false); - return; - } - - // Check to see if this is the last token on the #if[n]def line. - CheckEndOfDirective(isIfndef ? "#ifndef" : "#ifdef"); - - if (CurLexer->getConditionalStackDepth() == 0) { - // If the start of a top-level #ifdef, inform MIOpt. - if (!ReadAnyTokensBeforeDirective) { - assert(isIfndef && "#ifdef shouldn't reach here"); - CurLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo()); - } else - CurLexer->MIOpt.EnterTopLevelConditional(); - } - - IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); - MacroInfo *MI = getMacroInfo(MII); - - // If there is a macro, process it. - if (MI) // Mark it used. - MI->setIsUsed(true); - - // Should we include the stuff contained by this directive? - if (!MI == isIfndef) { - // Yes, remember that we are inside a conditional, then lex the next token. - CurLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false, - /*foundnonskip*/true, /*foundelse*/false); - } else { - // No, skip the contents of this block and return the first token after it. - SkipExcludedConditionalBlock(DirectiveTok.getLocation(), - /*Foundnonskip*/false, - /*FoundElse*/false); - } -} - -/// HandleIfDirective - Implements the #if directive. -/// -void Preprocessor::HandleIfDirective(Token &IfToken, - bool ReadAnyTokensBeforeDirective) { - ++NumIf; - - // Parse and evaluation the conditional expression. - IdentifierInfo *IfNDefMacro = 0; - bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro); - - // Should we include the stuff contained by this directive? - if (ConditionalTrue) { - // If this condition is equivalent to #ifndef X, and if this is the first - // directive seen, handle it for the multiple-include optimization. - if (CurLexer->getConditionalStackDepth() == 0) { - if (!ReadAnyTokensBeforeDirective && IfNDefMacro) - CurLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro); - else - CurLexer->MIOpt.EnterTopLevelConditional(); - } - - // Yes, remember that we are inside a conditional, then lex the next token. - CurLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false, - /*foundnonskip*/true, /*foundelse*/false); - } else { - // No, skip the contents of this block and return the first token after it. - SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false, - /*FoundElse*/false); - } -} - -/// HandleEndifDirective - Implements the #endif directive. -/// -void Preprocessor::HandleEndifDirective(Token &EndifToken) { - ++NumEndif; - - // Check that this is the whole directive. - CheckEndOfDirective("#endif"); - - PPConditionalInfo CondInfo; - if (CurLexer->popConditionalLevel(CondInfo)) { - // No conditionals on the stack: this is an #endif without an #if. - return Diag(EndifToken, diag::err_pp_endif_without_if); - } - - // If this the end of a top-level #endif, inform MIOpt. - if (CurLexer->getConditionalStackDepth() == 0) - CurLexer->MIOpt.ExitTopLevelConditional(); - - assert(!CondInfo.WasSkipping && !CurLexer->LexingRawMode && - "This code should only be reachable in the non-skipping case!"); -} - - -void Preprocessor::HandleElseDirective(Token &Result) { - ++NumElse; - - // #else directive in a non-skipping conditional... start skipping. - CheckEndOfDirective("#else"); - - PPConditionalInfo CI; - if (CurLexer->popConditionalLevel(CI)) - return Diag(Result, diag::pp_err_else_without_if); - - // If this is a top-level #else, inform the MIOpt. - if (CurLexer->getConditionalStackDepth() == 0) - CurLexer->MIOpt.EnterTopLevelConditional(); - - // If this is a #else with a #else before it, report the error. - if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else); - - // Finally, skip the rest of the contents of this block and return the first - // token after it. - return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, - /*FoundElse*/true); -} - -void Preprocessor::HandleElifDirective(Token &ElifToken) { - ++NumElse; - - // #elif directive in a non-skipping conditional... start skipping. - // We don't care what the condition is, because we will always skip it (since - // the block immediately before it was included). - DiscardUntilEndOfDirective(); - - PPConditionalInfo CI; - if (CurLexer->popConditionalLevel(CI)) - return Diag(ElifToken, diag::pp_err_elif_without_if); - - // If this is a top-level #elif, inform the MIOpt. - if (CurLexer->getConditionalStackDepth() == 0) - CurLexer->MIOpt.EnterTopLevelConditional(); - - // If this is a #elif with a #else before it, report the error. - if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else); - - // Finally, skip the rest of the contents of this block and return the first - // token after it. - return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, - /*FoundElse*/CI.FoundElse); -} - diff --git a/clang/Lex/PPExpressions.cpp b/clang/Lex/PPExpressions.cpp deleted file mode 100644 index cca76289176..00000000000 --- a/clang/Lex/PPExpressions.cpp +++ /dev/null @@ -1,639 +0,0 @@ -//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Preprocessor::EvaluateDirectiveExpression method, -// which parses and evaluates integer constant expressions for #if directives. -// -//===----------------------------------------------------------------------===// -// -// FIXME: implement testing for #assert's. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/LiteralSupport.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TokenKinds.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/SmallString.h" -using namespace clang; - -static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec, - Token &PeekTok, bool ValueLive, - Preprocessor &PP); - -/// DefinedTracker - This struct is used while parsing expressions to keep track -/// of whether !defined(X) has been seen. -/// -/// With this simple scheme, we handle the basic forms: -/// !defined(X) and !defined X -/// but we also trivially handle (silly) stuff like: -/// !!!defined(X) and +!defined(X) and !+!+!defined(X) and !(defined(X)). -struct DefinedTracker { - /// Each time a Value is evaluated, it returns information about whether the - /// parsed value is of the form defined(X), !defined(X) or is something else. - enum TrackerState { - DefinedMacro, // defined(X) - NotDefinedMacro, // !defined(X) - Unknown // Something else. - } State; - /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this - /// indicates the macro that was checked. - IdentifierInfo *TheMacro; -}; - - - -/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and -/// return the computed value in Result. Return true if there was an error -/// parsing. This function also returns information about the form of the -/// expression in DT. See above for information on what DT means. -/// -/// If ValueLive is false, then this value is being evaluated in a context where -/// the result is not used. As such, avoid diagnostics that relate to -/// evaluation. -static bool EvaluateValue(llvm::APSInt &Result, Token &PeekTok, - DefinedTracker &DT, bool ValueLive, - Preprocessor &PP) { - Result = 0; - DT.State = DefinedTracker::Unknown; - - // If this token's spelling is a pp-identifier, check to see if it is - // 'defined' or if it is a macro. Note that we check here because many - // keywords are pp-identifiers, so we can't check the kind. - if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { - // If this identifier isn't 'defined' and it wasn't macro expanded, it turns - // into a simple 0, unless it is the C++ keyword "true", in which case it - // turns into "1". - if (II->getPPKeywordID() != tok::pp_defined) { - PP.Diag(PeekTok, diag::warn_pp_undef_identifier, II->getName()); - Result = II->getTokenID() == tok::kw_true; - Result.setIsUnsigned(false); // "0" is signed intmax_t 0. - PP.LexNonComment(PeekTok); - return false; - } - - // Handle "defined X" and "defined(X)". - - // Get the next token, don't expand it. - PP.LexUnexpandedToken(PeekTok); - - // Two options, it can either be a pp-identifier or a (. - bool InParens = false; - if (PeekTok.is(tok::l_paren)) { - // Found a paren, remember we saw it and skip it. - InParens = true; - PP.LexUnexpandedToken(PeekTok); - } - - // If we don't have a pp-identifier now, this is an error. - if ((II = PeekTok.getIdentifierInfo()) == 0) { - PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); - return true; - } - - // Otherwise, we got an identifier, is it defined to something? - Result = II->hasMacroDefinition(); - Result.setIsUnsigned(false); // Result is signed intmax_t. - - // If there is a macro, mark it used. - if (Result != 0 && ValueLive) { - MacroInfo *Macro = PP.getMacroInfo(II); - Macro->setIsUsed(true); - } - - // Consume identifier. - PP.LexNonComment(PeekTok); - - // If we are in parens, ensure we have a trailing ). - if (InParens) { - if (PeekTok.isNot(tok::r_paren)) { - PP.Diag(PeekTok, diag::err_pp_missing_rparen); - return true; - } - // Consume the ). - PP.LexNonComment(PeekTok); - } - - // Success, remember that we saw defined(X). - DT.State = DefinedTracker::DefinedMacro; - DT.TheMacro = II; - return false; - } - - switch (PeekTok.getKind()) { - default: // Non-value token. - PP.Diag(PeekTok, diag::err_pp_expr_bad_token); - return true; - case tok::eom: - case tok::r_paren: - // If there is no expression, report and exit. - PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr); - return true; - case tok::numeric_constant: { - llvm::SmallString<64> IntegerBuffer; - IntegerBuffer.resize(PeekTok.getLength()); - const char *ThisTokBegin = &IntegerBuffer[0]; - unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin); - NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - PeekTok.getLocation(), PP); - if (Literal.hadError) - return true; // a diagnostic was already reported. - - if (Literal.isFloatingLiteral() || Literal.isImaginary) { - PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal); - return true; - } - assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); - - // long long is a C99 feature. - if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x - && Literal.isLongLong) - PP.Diag(PeekTok, diag::ext_longlong); - - // Parse the integer literal into Result. - if (Literal.GetIntegerValue(Result)) { - // Overflow parsing integer literal. - if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large); - Result.setIsUnsigned(true); - } else { - // Set the signedness of the result to match whether there was a U suffix - // or not. - Result.setIsUnsigned(Literal.isUnsigned); - - // Detect overflow based on whether the value is signed. If signed - // and if the value is too large, emit a warning "integer constant is so - // large that it is unsigned" e.g. on 12345678901234567890 where intmax_t - // is 64-bits. - if (!Literal.isUnsigned && Result.isNegative()) { - if (ValueLive)PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed); - Result.setIsUnsigned(true); - } - } - - // Consume the token. - PP.LexNonComment(PeekTok); - return false; - } - case tok::char_constant: { // 'x' - llvm::SmallString<32> CharBuffer; - CharBuffer.resize(PeekTok.getLength()); - const char *ThisTokBegin = &CharBuffer[0]; - unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin); - CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - PeekTok.getLocation(), PP); - if (Literal.hadError()) - return true; // A diagnostic was already emitted. - - // Character literals are always int or wchar_t, expand to intmax_t. - TargetInfo &TI = PP.getTargetInfo(); - unsigned NumBits = TI.getCharWidth(Literal.isWide()); - - // Set the width. - llvm::APSInt Val(NumBits); - // Set the value. - Val = Literal.getValue(); - // Set the signedness. - Val.setIsUnsigned(!TI.isCharSigned()); - - if (Result.getBitWidth() > Val.getBitWidth()) { - Result = Val.extend(Result.getBitWidth()); - } else { - assert(Result.getBitWidth() == Val.getBitWidth() && - "intmax_t smaller than char/wchar_t?"); - Result = Val; - } - - // Consume the token. - PP.LexNonComment(PeekTok); - return false; - } - case tok::l_paren: - PP.LexNonComment(PeekTok); // Eat the (. - // Parse the value and if there are any binary operators involved, parse - // them. - if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; - - // If this is a silly value like (X), which doesn't need parens, check for - // !(defined X). - if (PeekTok.is(tok::r_paren)) { - // Just use DT unmodified as our result. - } else { - if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP)) - return true; - - if (PeekTok.isNot(tok::r_paren)) { - PP.Diag(PeekTok, diag::err_pp_expected_rparen); - return true; - } - DT.State = DefinedTracker::Unknown; - } - PP.LexNonComment(PeekTok); // Eat the ). - return false; - - case tok::plus: - // Unary plus doesn't modify the value. - PP.LexNonComment(PeekTok); - return EvaluateValue(Result, PeekTok, DT, ValueLive, PP); - case tok::minus: { - SourceLocation Loc = PeekTok.getLocation(); - PP.LexNonComment(PeekTok); - if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; - // C99 6.5.3.3p3: The sign of the result matches the sign of the operand. - Result = -Result; - - bool Overflow = false; - if (Result.isUnsigned()) - Overflow = Result.isNegative(); - else if (Result.isMinSignedValue()) - Overflow = true; // -MININT is the only thing that overflows. - - // If this operator is live and overflowed, report the issue. - if (Overflow && ValueLive) - PP.Diag(Loc, diag::warn_pp_expr_overflow); - - DT.State = DefinedTracker::Unknown; - return false; - } - - case tok::tilde: - PP.LexNonComment(PeekTok); - if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; - // C99 6.5.3.3p4: The sign of the result matches the sign of the operand. - Result = ~Result; - DT.State = DefinedTracker::Unknown; - return false; - - case tok::exclaim: - PP.LexNonComment(PeekTok); - if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; - Result = !Result; - // C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed. - Result.setIsUnsigned(false); - - if (DT.State == DefinedTracker::DefinedMacro) - DT.State = DefinedTracker::NotDefinedMacro; - else if (DT.State == DefinedTracker::NotDefinedMacro) - DT.State = DefinedTracker::DefinedMacro; - return false; - - // FIXME: Handle #assert - } -} - - - -/// getPrecedence - Return the precedence of the specified binary operator -/// token. This returns: -/// ~0 - Invalid token. -/// 14 - *,/,% -/// 13 - -,+ -/// 12 - <<,>> -/// 11 - >=, <=, >, < -/// 10 - ==, != -/// 9 - & -/// 8 - ^ -/// 7 - | -/// 6 - && -/// 5 - || -/// 4 - ? -/// 3 - : -/// 0 - eom, ) -static unsigned getPrecedence(tok::TokenKind Kind) { - switch (Kind) { - default: return ~0U; - case tok::percent: - case tok::slash: - case tok::star: return 14; - case tok::plus: - case tok::minus: return 13; - case tok::lessless: - case tok::greatergreater: return 12; - case tok::lessequal: - case tok::less: - case tok::greaterequal: - case tok::greater: return 11; - case tok::exclaimequal: - case tok::equalequal: return 10; - case tok::amp: return 9; - case tok::caret: return 8; - case tok::pipe: return 7; - case tok::ampamp: return 6; - case tok::pipepipe: return 5; - case tok::question: return 4; - case tok::colon: return 3; - case tok::comma: return 2; - case tok::r_paren: return 0; // Lowest priority, end of expr. - case tok::eom: return 0; // Lowest priority, end of macro. - } -} - - -/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is -/// PeekTok, and whose precedence is PeekPrec. -/// -/// If ValueLive is false, then this value is being evaluated in a context where -/// the result is not used. As such, avoid diagnostics that relate to -/// evaluation. -static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec, - Token &PeekTok, bool ValueLive, - Preprocessor &PP) { - unsigned PeekPrec = getPrecedence(PeekTok.getKind()); - // If this token isn't valid, report the error. - if (PeekPrec == ~0U) { - PP.Diag(PeekTok, diag::err_pp_expr_bad_token); - return true; - } - - while (1) { - // If this token has a lower precedence than we are allowed to parse, return - // it so that higher levels of the recursion can parse it. - if (PeekPrec < MinPrec) - return false; - - tok::TokenKind Operator = PeekTok.getKind(); - - // If this is a short-circuiting operator, see if the RHS of the operator is - // dead. Note that this cannot just clobber ValueLive. Consider - // "0 && 1 ? 4 : 1 / 0", which is parsed as "(0 && 1) ? 4 : (1 / 0)". In - // this example, the RHS of the && being dead does not make the rest of the - // expr dead. - bool RHSIsLive; - if (Operator == tok::ampamp && LHS == 0) - RHSIsLive = false; // RHS of "0 && x" is dead. - else if (Operator == tok::pipepipe && LHS != 0) - RHSIsLive = false; // RHS of "1 || x" is dead. - else if (Operator == tok::question && LHS == 0) - RHSIsLive = false; // RHS (x) of "0 ? x : y" is dead. - else - RHSIsLive = ValueLive; - - // Consume the operator, saving the operator token for error reporting. - Token OpToken = PeekTok; - PP.LexNonComment(PeekTok); - - llvm::APSInt RHS(LHS.getBitWidth()); - // Parse the RHS of the operator. - DefinedTracker DT; - if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true; - - // Remember the precedence of this operator and get the precedence of the - // operator immediately to the right of the RHS. - unsigned ThisPrec = PeekPrec; - PeekPrec = getPrecedence(PeekTok.getKind()); - - // If this token isn't valid, report the error. - if (PeekPrec == ~0U) { - PP.Diag(PeekTok, diag::err_pp_expr_bad_token); - return true; - } - - bool isRightAssoc = Operator == tok::question; - - // Get the precedence of the operator to the right of the RHS. If it binds - // more tightly with RHS than we do, evaluate it completely first. - if (ThisPrec < PeekPrec || - (ThisPrec == PeekPrec && isRightAssoc)) { - if (EvaluateDirectiveSubExpr(RHS, ThisPrec+1, PeekTok, RHSIsLive, PP)) - return true; - PeekPrec = getPrecedence(PeekTok.getKind()); - } - assert(PeekPrec <= ThisPrec && "Recursion didn't work!"); - - // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if - // either operand is unsigned. Don't do this for x and y in "x ? y : z". - llvm::APSInt Res(LHS.getBitWidth()); - if (Operator != tok::question) { - Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned()); - // If this just promoted something from signed to unsigned, and if the - // value was negative, warn about it. - if (ValueLive && Res.isUnsigned()) { - if (!LHS.isUnsigned() && LHS.isNegative()) - PP.Diag(OpToken, diag::warn_pp_convert_lhs_to_positive, - LHS.toStringSigned() + " to " + LHS.toStringUnsigned()); - if (!RHS.isUnsigned() && RHS.isNegative()) - PP.Diag(OpToken, diag::warn_pp_convert_rhs_to_positive, - RHS.toStringSigned() + " to " + RHS.toStringUnsigned()); - } - LHS.setIsUnsigned(Res.isUnsigned()); - RHS.setIsUnsigned(Res.isUnsigned()); - } - - // FIXME: All of these should detect and report overflow?? - bool Overflow = false; - switch (Operator) { - default: assert(0 && "Unknown operator token!"); - case tok::percent: - if (RHS == 0) { - if (ValueLive) PP.Diag(OpToken, diag::err_pp_remainder_by_zero); - return true; - } - Res = LHS % RHS; - break; - case tok::slash: - if (RHS == 0) { - if (ValueLive) PP.Diag(OpToken, diag::err_pp_division_by_zero); - return true; - } - Res = LHS / RHS; - if (LHS.isSigned()) - Overflow = LHS.isMinSignedValue() && RHS.isAllOnesValue(); // MININT/-1 - break; - case tok::star: - Res = LHS * RHS; - if (LHS != 0 && RHS != 0) - Overflow = Res/RHS != LHS || Res/LHS != RHS; - break; - case tok::lessless: { - // Determine whether overflow is about to happen. - unsigned ShAmt = static_cast(RHS.getLimitedValue()); - if (ShAmt >= LHS.getBitWidth()) - Overflow = true, ShAmt = LHS.getBitWidth()-1; - else if (LHS.isUnsigned()) - Overflow = ShAmt > LHS.countLeadingZeros(); - else if (LHS.isNonNegative()) - Overflow = ShAmt >= LHS.countLeadingZeros(); // Don't allow sign change. - else - Overflow = ShAmt >= LHS.countLeadingOnes(); - - Res = LHS << ShAmt; - break; - } - case tok::greatergreater: { - // Determine whether overflow is about to happen. - unsigned ShAmt = static_cast(RHS.getLimitedValue()); - if (ShAmt >= LHS.getBitWidth()) - Overflow = true, ShAmt = LHS.getBitWidth()-1; - Res = LHS >> ShAmt; - break; - } - case tok::plus: - Res = LHS + RHS; - if (LHS.isUnsigned()) - Overflow = Res.ult(LHS); - else if (LHS.isNonNegative() == RHS.isNonNegative() && - Res.isNonNegative() != LHS.isNonNegative()) - Overflow = true; // Overflow for signed addition. - break; - case tok::minus: - Res = LHS - RHS; - if (LHS.isUnsigned()) - Overflow = Res.ugt(LHS); - else if (LHS.isNonNegative() != RHS.isNonNegative() && - Res.isNonNegative() != LHS.isNonNegative()) - Overflow = true; // Overflow for signed subtraction. - break; - case tok::lessequal: - Res = LHS <= RHS; - Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) - break; - case tok::less: - Res = LHS < RHS; - Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) - break; - case tok::greaterequal: - Res = LHS >= RHS; - Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) - break; - case tok::greater: - Res = LHS > RHS; - Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) - break; - case tok::exclaimequal: - Res = LHS != RHS; - Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed) - break; - case tok::equalequal: - Res = LHS == RHS; - Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed) - break; - case tok::amp: - Res = LHS & RHS; - break; - case tok::caret: - Res = LHS ^ RHS; - break; - case tok::pipe: - Res = LHS | RHS; - break; - case tok::ampamp: - Res = (LHS != 0 && RHS != 0); - Res.setIsUnsigned(false); // C99 6.5.13p3, result is always int (signed) - break; - case tok::pipepipe: - Res = (LHS != 0 || RHS != 0); - Res.setIsUnsigned(false); // C99 6.5.14p3, result is always int (signed) - break; - case tok::comma: - PP.Diag(OpToken, diag::ext_pp_comma_expr); - Res = RHS; // LHS = LHS,RHS -> RHS. - break; - case tok::question: { - // Parse the : part of the expression. - if (PeekTok.isNot(tok::colon)) { - PP.Diag(OpToken, diag::err_pp_question_without_colon); - return true; - } - // Consume the :. - PP.LexNonComment(PeekTok); - - // Evaluate the value after the :. - bool AfterColonLive = ValueLive && LHS == 0; - llvm::APSInt AfterColonVal(LHS.getBitWidth()); - DefinedTracker DT; - if (EvaluateValue(AfterColonVal, PeekTok, DT, AfterColonLive, PP)) - return true; - - // Parse anything after the : RHS that has a higher precedence than ?. - if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec+1, - PeekTok, AfterColonLive, PP)) - return true; - - // Now that we have the condition, the LHS and the RHS of the :, evaluate. - Res = LHS != 0 ? RHS : AfterColonVal; - - // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if - // either operand is unsigned. - Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned()); - - // Figure out the precedence of the token after the : part. - PeekPrec = getPrecedence(PeekTok.getKind()); - break; - } - case tok::colon: - // Don't allow :'s to float around without being part of ?: exprs. - PP.Diag(OpToken, diag::err_pp_colon_without_question); - return true; - } - - // If this operator is live and overflowed, report the issue. - if (Overflow && ValueLive) - PP.Diag(OpToken, diag::warn_pp_expr_overflow); - - // Put the result back into 'LHS' for our next iteration. - LHS = Res; - } - - return false; -} - -/// EvaluateDirectiveExpression - Evaluate an integer constant expression that -/// may occur after a #if or #elif directive. If the expression is equivalent -/// to "!defined(X)" return X in IfNDefMacro. -bool Preprocessor:: -EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { - // Peek ahead one token. - Token Tok; - Lex(Tok); - - // C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t. - unsigned BitWidth = getTargetInfo().getIntMaxTWidth(); - - llvm::APSInt ResVal(BitWidth); - DefinedTracker DT; - if (EvaluateValue(ResVal, Tok, DT, true, *this)) { - // Parse error, skip the rest of the macro line. - if (Tok.isNot(tok::eom)) - DiscardUntilEndOfDirective(); - return false; - } - - // If we are at the end of the expression after just parsing a value, there - // must be no (unparenthesized) binary operators involved, so we can exit - // directly. - if (Tok.is(tok::eom)) { - // If the expression we parsed was of the form !defined(macro), return the - // macro in IfNDefMacro. - if (DT.State == DefinedTracker::NotDefinedMacro) - IfNDefMacro = DT.TheMacro; - - return ResVal != 0; - } - - // Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the - // operator and the stuff after it. - if (EvaluateDirectiveSubExpr(ResVal, 1, Tok, true, *this)) { - // Parse error, skip the rest of the macro line. - if (Tok.isNot(tok::eom)) - DiscardUntilEndOfDirective(); - return false; - } - - // If we aren't at the tok::eom token, something bad happened, like an extra - // ')' token. - if (Tok.isNot(tok::eom)) { - Diag(Tok, diag::err_pp_expected_eol); - DiscardUntilEndOfDirective(); - } - - return ResVal != 0; -} - diff --git a/clang/Lex/PPLexerChange.cpp b/clang/Lex/PPLexerChange.cpp deleted file mode 100644 index bd0ff7f94a1..00000000000 --- a/clang/Lex/PPLexerChange.cpp +++ /dev/null @@ -1,401 +0,0 @@ -//===--- PPLexerChange.cpp - Handle changing lexers in the preprocessor ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements pieces of the Preprocessor interface that manage the -// current lexer stack. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" -using namespace clang; - -PPCallbacks::~PPCallbacks() { -} - - -//===----------------------------------------------------------------------===// -// Miscellaneous Methods. -//===----------------------------------------------------------------------===// - -/// isInPrimaryFile - Return true if we're in the top-level file, not in a -/// #include. This looks through macro expansions and active _Pragma lexers. -bool Preprocessor::isInPrimaryFile() const { - if (CurLexer && !CurLexer->Is_PragmaLexer) - return IncludeMacroStack.empty(); - - // If there are any stacked lexers, we're in a #include. - assert(IncludeMacroStack[0].TheLexer && - !IncludeMacroStack[0].TheLexer->Is_PragmaLexer && - "Top level include stack isn't our primary lexer?"); - for (unsigned i = 1, e = IncludeMacroStack.size(); i != e; ++i) - if (IncludeMacroStack[i].TheLexer && - !IncludeMacroStack[i].TheLexer->Is_PragmaLexer) - return false; - return true; -} - -/// getCurrentLexer - Return the current file lexer being lexed from. Note -/// that this ignores any potentially active macro expansions and _Pragma -/// expansions going on at the time. -Lexer *Preprocessor::getCurrentFileLexer() const { - if (CurLexer && !CurLexer->Is_PragmaLexer) return CurLexer; - - // Look for a stacked lexer. - for (unsigned i = IncludeMacroStack.size(); i != 0; --i) { - Lexer *L = IncludeMacroStack[i-1].TheLexer; - if (L && !L->Is_PragmaLexer) // Ignore macro & _Pragma expansions. - return L; - } - return 0; -} - -/// LookAhead - This peeks ahead N tokens and returns that token without -/// consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) returns -/// the token after Tok, etc. -/// -/// NOTE: is a relatively expensive method, so it should not be used in common -/// code paths if possible! -/// -Token Preprocessor::LookAhead(unsigned N) { - // FIXME: Optimize the case where multiple lookahead calls are used back to - // back. Consider if the the parser contained (dynamically): - // Lookahead(1); Lookahead(1); Lookahead(1) - // This would return the same token 3 times, but would end up making lots of - // token stream lexers to do it. To handle this common case, see if the top - // of the lexer stack is a TokenStreamLexer with macro expansion disabled. If - // so, see if it has 'N' tokens available in it. If so, just return the - // token. - - // FIXME: Optimize the case when the parser does multiple nearby lookahead - // calls. For example, consider: - // Lookahead(0); Lookahead(1); Lookahead(2); - // The previous optimization won't apply, and there won't be any space left in - // the array that was previously new'd. To handle this, always round up the - // size we new to a multiple of 16 tokens. If the previous buffer has space - // left, we can just grow it. This means we only have to do the new 1/16th as - // often. - - Token *LookaheadTokens = new Token[N]; - - // Read N+1 tokens into LookaheadTokens. After this loop, Tok is the token - // to return. - Token Tok; - unsigned NumTokens = 0; - for (; N != ~0U; --N, ++NumTokens) { - Lex(Tok); - LookaheadTokens[NumTokens] = Tok; - - // If we got to EOF, don't lex past it. This will cause LookAhead to return - // the EOF token. - if (Tok.is(tok::eof)) - break; - } - - // Okay, at this point, we have the token we want to return in Tok. However, - // we read it and a bunch of other stuff (in LookaheadTokens) that we must - // allow subsequent calls to 'Lex' to return. To do this, we push a new token - // lexer onto the lexer stack with the tokens we read here. This passes - // ownership of LookaheadTokens to EnterTokenStream. - // - // Note that we disable macro expansion of the tokens from this buffer, since - // any macros have already been expanded, and the internal preprocessor state - // may already read past new macros. Consider something like LookAhead(1) on - // X - // #define X 14 - // Y - // The lookahead call should return 'Y', and the next Lex call should return - // 'X' even though X -> 14 has already been entered as a macro. - // - EnterTokenStream(LookaheadTokens, NumTokens, true /*DisableExpansion*/, - true /*OwnsTokens*/); - return Tok; -} - - -//===----------------------------------------------------------------------===// -// Methods for Entering and Callbacks for leaving various contexts -//===----------------------------------------------------------------------===// - -/// EnterSourceFile - Add a source file to the top of the include stack and -/// start lexing tokens from it instead of the current buffer. Return true -/// on failure. -void Preprocessor::EnterSourceFile(unsigned FileID, - const DirectoryLookup *CurDir) { - assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); - ++NumEnteredSourceFiles; - - if (MaxIncludeStackDepth < IncludeMacroStack.size()) - MaxIncludeStackDepth = IncludeMacroStack.size(); - - Lexer *TheLexer = new Lexer(SourceLocation::getFileLoc(FileID, 0), *this); - EnterSourceFileWithLexer(TheLexer, CurDir); -} - -/// EnterSourceFile - Add a source file to the top of the include stack and -/// start lexing tokens from it instead of the current buffer. -void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, - const DirectoryLookup *CurDir) { - - // Add the current lexer to the include stack. - if (CurLexer || CurTokenLexer) - IncludeMacroStack.push_back(IncludeStackInfo(CurLexer, CurDirLookup, - CurTokenLexer)); - - CurLexer = TheLexer; - CurDirLookup = CurDir; - CurTokenLexer = 0; - - // Notify the client, if desired, that we are in a new source file. - if (Callbacks && !CurLexer->Is_PragmaLexer) { - DirectoryLookup::DirType FileType = DirectoryLookup::NormalHeaderDir; - - // Get the file entry for the current file. - if (const FileEntry *FE = - SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc())) - FileType = HeaderInfo.getFileDirFlavor(FE); - - Callbacks->FileChanged(CurLexer->getFileLoc(), - PPCallbacks::EnterFile, FileType); - } -} - - - -/// EnterMacro - Add a Macro to the top of the include stack and start lexing -/// tokens from it instead of the current buffer. -void Preprocessor::EnterMacro(Token &Tok, MacroArgs *Args) { - IncludeMacroStack.push_back(IncludeStackInfo(CurLexer, CurDirLookup, - CurTokenLexer)); - CurLexer = 0; - CurDirLookup = 0; - - if (NumCachedTokenLexers == 0) { - CurTokenLexer = new TokenLexer(Tok, Args, *this); - } else { - CurTokenLexer = TokenLexerCache[--NumCachedTokenLexers]; - CurTokenLexer->Init(Tok, Args); - } -} - -/// EnterTokenStream - Add a "macro" context to the top of the include stack, -/// which will cause the lexer to start returning the specified tokens. -/// -/// If DisableMacroExpansion is true, tokens lexed from the token stream will -/// not be subject to further macro expansion. Otherwise, these tokens will -/// be re-macro-expanded when/if expansion is enabled. -/// -/// If OwnsTokens is false, this method assumes that the specified stream of -/// tokens has a permanent owner somewhere, so they do not need to be copied. -/// If it is true, it assumes the array of tokens is allocated with new[] and -/// must be freed. -/// -void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks, - bool DisableMacroExpansion, - bool OwnsTokens) { - // Save our current state. - IncludeMacroStack.push_back(IncludeStackInfo(CurLexer, CurDirLookup, - CurTokenLexer)); - CurLexer = 0; - CurDirLookup = 0; - - // Create a macro expander to expand from the specified token stream. - if (NumCachedTokenLexers == 0) { - CurTokenLexer = new TokenLexer(Toks, NumToks, DisableMacroExpansion, - OwnsTokens, *this); - } else { - CurTokenLexer = TokenLexerCache[--NumCachedTokenLexers]; - CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens); - } -} - -/// HandleEndOfFile - This callback is invoked when the lexer hits the end of -/// the current file. This either returns the EOF token or pops a level off -/// the include stack and keeps going. -bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { - assert(!CurTokenLexer && - "Ending a file when currently in a macro!"); - - // See if this file had a controlling macro. - if (CurLexer) { // Not ending a macro, ignore it. - if (const IdentifierInfo *ControllingMacro = - CurLexer->MIOpt.GetControllingMacroAtEndOfFile()) { - // Okay, this has a controlling macro, remember in PerFileInfo. - if (const FileEntry *FE = - SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc())) - HeaderInfo.SetFileControllingMacro(FE, ControllingMacro); - } - } - - // If this is a #include'd file, pop it off the include stack and continue - // lexing the #includer file. - if (!IncludeMacroStack.empty()) { - // We're done with the #included file. - RemoveTopOfLexerStack(); - - // Notify the client, if desired, that we are in a new source file. - if (Callbacks && !isEndOfMacro && CurLexer) { - DirectoryLookup::DirType FileType = DirectoryLookup::NormalHeaderDir; - - // Get the file entry for the current file. - if (const FileEntry *FE = - SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc())) - FileType = HeaderInfo.getFileDirFlavor(FE); - - Callbacks->FileChanged(CurLexer->getSourceLocation(CurLexer->BufferPtr), - PPCallbacks::ExitFile, FileType); - } - - // Client should lex another token. - return false; - } - - // If the file ends with a newline, form the EOF token on the newline itself, - // rather than "on the line following it", which doesn't exist. This makes - // diagnostics relating to the end of file include the last file that the user - // actually typed, which is goodness. - const char *EndPos = CurLexer->BufferEnd; - if (EndPos != CurLexer->BufferStart && - (EndPos[-1] == '\n' || EndPos[-1] == '\r')) { - --EndPos; - - // Handle \n\r and \r\n: - if (EndPos != CurLexer->BufferStart && - (EndPos[-1] == '\n' || EndPos[-1] == '\r') && - EndPos[-1] != EndPos[0]) - --EndPos; - } - - Result.startToken(); - CurLexer->BufferPtr = EndPos; - CurLexer->FormTokenWithChars(Result, EndPos); - Result.setKind(tok::eof); - - // We're done with the #included file. - delete CurLexer; - CurLexer = 0; - - // This is the end of the top-level file. If the diag::pp_macro_not_used - // diagnostic is enabled, look for macros that have not been used. - if (Diags.getDiagnosticLevel(diag::pp_macro_not_used) != Diagnostic::Ignored){ - for (llvm::DenseMap::iterator I = - Macros.begin(), E = Macros.end(); I != E; ++I) { - if (!I->second->isUsed()) - Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used); - } - } - return true; -} - -/// HandleEndOfTokenLexer - This callback is invoked when the current TokenLexer -/// hits the end of its token stream. -bool Preprocessor::HandleEndOfTokenLexer(Token &Result) { - assert(CurTokenLexer && !CurLexer && - "Ending a macro when currently in a #include file!"); - - // Delete or cache the now-dead macro expander. - if (NumCachedTokenLexers == TokenLexerCacheSize) - delete CurTokenLexer; - else - TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer; - - // Handle this like a #include file being popped off the stack. - CurTokenLexer = 0; - return HandleEndOfFile(Result, true); -} - -/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the -/// lexer stack. This should only be used in situations where the current -/// state of the top-of-stack lexer is unknown. -void Preprocessor::RemoveTopOfLexerStack() { - assert(!IncludeMacroStack.empty() && "Ran out of stack entries to load"); - - if (CurTokenLexer) { - // Delete or cache the now-dead macro expander. - if (NumCachedTokenLexers == TokenLexerCacheSize) - delete CurTokenLexer; - else - TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer; - } else { - delete CurLexer; - } - CurLexer = IncludeMacroStack.back().TheLexer; - CurDirLookup = IncludeMacroStack.back().TheDirLookup; - CurTokenLexer = IncludeMacroStack.back().TheTokenLexer; - IncludeMacroStack.pop_back(); -} - -/// HandleMicrosoftCommentPaste - When the macro expander pastes together a -/// comment (/##/) in microsoft mode, this method handles updating the current -/// state, returning the token on the next source line. -void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { - assert(CurTokenLexer && !CurLexer && - "Pasted comment can only be formed from macro"); - - // We handle this by scanning for the closest real lexer, switching it to - // raw mode and preprocessor mode. This will cause it to return \n as an - // explicit EOM token. - Lexer *FoundLexer = 0; - bool LexerWasInPPMode = false; - for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) { - IncludeStackInfo &ISI = *(IncludeMacroStack.end()-i-1); - if (ISI.TheLexer == 0) continue; // Scan for a real lexer. - - // Once we find a real lexer, mark it as raw mode (disabling macro - // expansions) and preprocessor mode (return EOM). We know that the lexer - // was *not* in raw mode before, because the macro that the comment came - // from was expanded. However, it could have already been in preprocessor - // mode (#if COMMENT) in which case we have to return it to that mode and - // return EOM. - FoundLexer = ISI.TheLexer; - FoundLexer->LexingRawMode = true; - LexerWasInPPMode = FoundLexer->ParsingPreprocessorDirective; - FoundLexer->ParsingPreprocessorDirective = true; - break; - } - - // Okay, we either found and switched over the lexer, or we didn't find a - // lexer. In either case, finish off the macro the comment came from, getting - // the next token. - if (!HandleEndOfTokenLexer(Tok)) Lex(Tok); - - // Discarding comments as long as we don't have EOF or EOM. This 'comments - // out' the rest of the line, including any tokens that came from other macros - // that were active, as in: - // #define submacro a COMMENT b - // submacro c - // which should lex to 'a' only: 'b' and 'c' should be removed. - while (Tok.isNot(tok::eom) && Tok.isNot(tok::eof)) - Lex(Tok); - - // If we got an eom token, then we successfully found the end of the line. - if (Tok.is(tok::eom)) { - assert(FoundLexer && "Can't get end of line without an active lexer"); - // Restore the lexer back to normal mode instead of raw mode. - FoundLexer->LexingRawMode = false; - - // If the lexer was already in preprocessor mode, just return the EOM token - // to finish the preprocessor line. - if (LexerWasInPPMode) return; - - // Otherwise, switch out of PP mode and return the next lexed token. - FoundLexer->ParsingPreprocessorDirective = false; - return Lex(Tok); - } - - // If we got an EOF token, then we reached the end of the token stream but - // didn't find an explicit \n. This can only happen if there was no lexer - // active (an active lexer would return EOM at EOF if there was no \n in - // preprocessor directive mode), so just return EOF as our token. - assert(!FoundLexer && "Lexer should return EOM before EOF in PP mode"); -} diff --git a/clang/Lex/PPMacroExpansion.cpp b/clang/Lex/PPMacroExpansion.cpp deleted file mode 100644 index 8218d0ac06e..00000000000 --- a/clang/Lex/PPMacroExpansion.cpp +++ /dev/null @@ -1,523 +0,0 @@ -//===--- MacroExpansion.cpp - Top level Macro Expansion -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the top level handling of macro expasion for the -// preprocessor. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Preprocessor.h" -#include "MacroArgs.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/Diagnostic.h" -using namespace clang; - -/// setMacroInfo - Specify a macro for this identifier. -/// -void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) { - if (MI == 0) { - if (II->hasMacroDefinition()) { - Macros.erase(II); - II->setHasMacroDefinition(false); - } - } else { - Macros[II] = MI; - II->setHasMacroDefinition(true); - } -} - -/// RegisterBuiltinMacro - Register the specified identifier in the identifier -/// table and mark it as a builtin macro to be expanded. -IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) { - // Get the identifier. - IdentifierInfo *Id = getIdentifierInfo(Name); - - // Mark it as being a macro that is builtin. - MacroInfo *MI = new MacroInfo(SourceLocation()); - MI->setIsBuiltinMacro(); - setMacroInfo(Id, MI); - return Id; -} - - -/// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the -/// identifier table. -void Preprocessor::RegisterBuiltinMacros() { - Ident__LINE__ = RegisterBuiltinMacro("__LINE__"); - Ident__FILE__ = RegisterBuiltinMacro("__FILE__"); - Ident__DATE__ = RegisterBuiltinMacro("__DATE__"); - Ident__TIME__ = RegisterBuiltinMacro("__TIME__"); - Ident_Pragma = RegisterBuiltinMacro("_Pragma"); - - // GCC Extensions. - Ident__BASE_FILE__ = RegisterBuiltinMacro("__BASE_FILE__"); - Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro("__INCLUDE_LEVEL__"); - Ident__TIMESTAMP__ = RegisterBuiltinMacro("__TIMESTAMP__"); -} - -/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token -/// in its expansion, currently expands to that token literally. -static bool isTrivialSingleTokenExpansion(const MacroInfo *MI, - const IdentifierInfo *MacroIdent, - Preprocessor &PP) { - IdentifierInfo *II = MI->getReplacementToken(0).getIdentifierInfo(); - - // If the token isn't an identifier, it's always literally expanded. - if (II == 0) return true; - - // If the identifier is a macro, and if that macro is enabled, it may be - // expanded so it's not a trivial expansion. - if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled() && - // Fast expanding "#define X X" is ok, because X would be disabled. - II != MacroIdent) - return false; - - // If this is an object-like macro invocation, it is safe to trivially expand - // it. - if (MI->isObjectLike()) return true; - - // If this is a function-like macro invocation, it's safe to trivially expand - // as long as the identifier is not a macro argument. - for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); - I != E; ++I) - if (*I == II) - return false; // Identifier is a macro argument. - - return true; -} - - -/// isNextPPTokenLParen - Determine whether the next preprocessor token to be -/// lexed is a '('. If so, consume the token and return true, if not, this -/// method should have no observable side-effect on the lexed tokens. -bool Preprocessor::isNextPPTokenLParen() { - // Do some quick tests for rejection cases. - unsigned Val; - if (CurLexer) - Val = CurLexer->isNextPPTokenLParen(); - else - Val = CurTokenLexer->isNextTokenLParen(); - - if (Val == 2) { - // We have run off the end. If it's a source file we don't - // examine enclosing ones (C99 5.1.1.2p4). Otherwise walk up the - // macro stack. - if (CurLexer) - return false; - for (unsigned i = IncludeMacroStack.size(); i != 0; --i) { - IncludeStackInfo &Entry = IncludeMacroStack[i-1]; - if (Entry.TheLexer) - Val = Entry.TheLexer->isNextPPTokenLParen(); - else - Val = Entry.TheTokenLexer->isNextTokenLParen(); - - if (Val != 2) - break; - - // Ran off the end of a source file? - if (Entry.TheLexer) - return false; - } - } - - // Okay, if we know that the token is a '(', lex it and return. Otherwise we - // have found something that isn't a '(' or we found the end of the - // translation unit. In either case, return false. - if (Val != 1) - return false; - - Token Tok; - LexUnexpandedToken(Tok); - assert(Tok.is(tok::l_paren) && "Error computing l-paren-ness?"); - return true; -} - -/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be -/// expanded as a macro, handle it and return the next token as 'Identifier'. -bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, - MacroInfo *MI) { - // If this is a macro exapnsion in the "#if !defined(x)" line for the file, - // then the macro could expand to different things in other contexts, we need - // to disable the optimization in this case. - if (CurLexer) CurLexer->MIOpt.ExpandedMacro(); - - // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. - if (MI->isBuiltinMacro()) { - ExpandBuiltinMacro(Identifier); - return false; - } - - /// Args - If this is a function-like macro expansion, this contains, - /// for each macro argument, the list of tokens that were provided to the - /// invocation. - MacroArgs *Args = 0; - - // If this is a function-like macro, read the arguments. - if (MI->isFunctionLike()) { - // C99 6.10.3p10: If the preprocessing token immediately after the the macro - // name isn't a '(', this macro should not be expanded. Otherwise, consume - // it. - if (!isNextPPTokenLParen()) - return true; - - // Remember that we are now parsing the arguments to a macro invocation. - // Preprocessor directives used inside macro arguments are not portable, and - // this enables the warning. - InMacroArgs = true; - Args = ReadFunctionLikeMacroArgs(Identifier, MI); - - // Finished parsing args. - InMacroArgs = false; - - // If there was an error parsing the arguments, bail out. - if (Args == 0) return false; - - ++NumFnMacroExpanded; - } else { - ++NumMacroExpanded; - } - - // Notice that this macro has been used. - MI->setIsUsed(true); - - // If we started lexing a macro, enter the macro expansion body. - - // If this macro expands to no tokens, don't bother to push it onto the - // expansion stack, only to take it right back off. - if (MI->getNumTokens() == 0) { - // No need for arg info. - if (Args) Args->destroy(); - - // Ignore this macro use, just return the next token in the current - // buffer. - bool HadLeadingSpace = Identifier.hasLeadingSpace(); - bool IsAtStartOfLine = Identifier.isAtStartOfLine(); - - Lex(Identifier); - - // If the identifier isn't on some OTHER line, inherit the leading - // whitespace/first-on-a-line property of this token. This handles - // stuff like "! XX," -> "! ," and " XX," -> " ,", when XX is - // empty. - if (!Identifier.isAtStartOfLine()) { - if (IsAtStartOfLine) Identifier.setFlag(Token::StartOfLine); - if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace); - } - ++NumFastMacroExpanded; - return false; - - } else if (MI->getNumTokens() == 1 && - isTrivialSingleTokenExpansion(MI, Identifier.getIdentifierInfo(), - *this)){ - // Otherwise, if this macro expands into a single trivially-expanded - // token: expand it now. This handles common cases like - // "#define VAL 42". - - // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro - // identifier to the expanded token. - bool isAtStartOfLine = Identifier.isAtStartOfLine(); - bool hasLeadingSpace = Identifier.hasLeadingSpace(); - - // Remember where the token is instantiated. - SourceLocation InstantiateLoc = Identifier.getLocation(); - - // Replace the result token. - Identifier = MI->getReplacementToken(0); - - // Restore the StartOfLine/LeadingSpace markers. - Identifier.setFlagValue(Token::StartOfLine , isAtStartOfLine); - Identifier.setFlagValue(Token::LeadingSpace, hasLeadingSpace); - - // Update the tokens location to include both its logical and physical - // locations. - SourceLocation Loc = - SourceMgr.getInstantiationLoc(Identifier.getLocation(), InstantiateLoc); - Identifier.setLocation(Loc); - - // If this is #define X X, we must mark the result as unexpandible. - if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) - if (getMacroInfo(NewII) == MI) - Identifier.setFlag(Token::DisableExpand); - - // Since this is not an identifier token, it can't be macro expanded, so - // we're done. - ++NumFastMacroExpanded; - return false; - } - - // Start expanding the macro. - EnterMacro(Identifier, Args); - - // Now that the macro is at the top of the include stack, ask the - // preprocessor to read the next token from it. - Lex(Identifier); - return false; -} - -/// ReadFunctionLikeMacroArgs - After reading "MACRO(", this method is -/// invoked to read all of the actual arguments specified for the macro -/// invocation. This returns null on error. -MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, - MacroInfo *MI) { - // The number of fixed arguments to parse. - unsigned NumFixedArgsLeft = MI->getNumArgs(); - bool isVariadic = MI->isVariadic(); - - // Outer loop, while there are more arguments, keep reading them. - Token Tok; - Tok.setKind(tok::comma); - --NumFixedArgsLeft; // Start reading the first arg. - - // ArgTokens - Build up a list of tokens that make up each argument. Each - // argument is separated by an EOF token. Use a SmallVector so we can avoid - // heap allocations in the common case. - llvm::SmallVector ArgTokens; - - unsigned NumActuals = 0; - while (Tok.is(tok::comma)) { - // C99 6.10.3p11: Keep track of the number of l_parens we have seen. Note - // that we already consumed the first one. - unsigned NumParens = 0; - - while (1) { - // Read arguments as unexpanded tokens. This avoids issues, e.g., where - // an argument value in a macro could expand to ',' or '(' or ')'. - LexUnexpandedToken(Tok); - - if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(" & "#if f(\n" - Diag(MacroName, diag::err_unterm_macro_invoc); - // Do not lose the EOF/EOM. Return it to the client. - MacroName = Tok; - return 0; - } else if (Tok.is(tok::r_paren)) { - // If we found the ) token, the macro arg list is done. - if (NumParens-- == 0) - break; - } else if (Tok.is(tok::l_paren)) { - ++NumParens; - } else if (Tok.is(tok::comma) && NumParens == 0) { - // Comma ends this argument if there are more fixed arguments expected. - if (NumFixedArgsLeft) - break; - - // If this is not a variadic macro, too many args were specified. - if (!isVariadic) { - // Emit the diagnostic at the macro name in case there is a missing ). - // Emitting it at the , could be far away from the macro name. - Diag(MacroName, diag::err_too_many_args_in_macro_invoc); - return 0; - } - // Otherwise, continue to add the tokens to this variable argument. - } else if (Tok.is(tok::comment) && !KeepMacroComments) { - // If this is a comment token in the argument list and we're just in - // -C mode (not -CC mode), discard the comment. - continue; - } else if (Tok.is(tok::identifier)) { - // Reading macro arguments can cause macros that we are currently - // expanding from to be popped off the expansion stack. Doing so causes - // them to be reenabled for expansion. Here we record whether any - // identifiers we lex as macro arguments correspond to disabled macros. - // If so, we mark the token as noexpand. This is a subtle aspect of - // C99 6.10.3.4p2. - if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo())) - if (!MI->isEnabled()) - Tok.setFlag(Token::DisableExpand); - } - - ArgTokens.push_back(Tok); - } - - // Empty arguments are standard in C99 and supported as an extension in - // other modes. - if (ArgTokens.empty() && !Features.C99) - Diag(Tok, diag::ext_empty_fnmacro_arg); - - // Add a marker EOF token to the end of the token list for this argument. - Token EOFTok; - EOFTok.startToken(); - EOFTok.setKind(tok::eof); - EOFTok.setLocation(Tok.getLocation()); - EOFTok.setLength(0); - ArgTokens.push_back(EOFTok); - ++NumActuals; - --NumFixedArgsLeft; - }; - - // Okay, we either found the r_paren. Check to see if we parsed too few - // arguments. - unsigned MinArgsExpected = MI->getNumArgs(); - - // See MacroArgs instance var for description of this. - bool isVarargsElided = false; - - if (NumActuals < MinArgsExpected) { - // There are several cases where too few arguments is ok, handle them now. - if (NumActuals+1 == MinArgsExpected && MI->isVariadic()) { - // Varargs where the named vararg parameter is missing: ok as extension. - // #define A(x, ...) - // A("blah") - Diag(Tok, diag::ext_missing_varargs_arg); - - // Remember this occurred if this is a C99 macro invocation with at least - // one actual argument. - isVarargsElided = MI->isC99Varargs() && MI->getNumArgs() > 1; - } else if (MI->getNumArgs() == 1) { - // #define A(x) - // A() - // is ok because it is an empty argument. - - // Empty arguments are standard in C99 and supported as an extension in - // other modes. - if (ArgTokens.empty() && !Features.C99) - Diag(Tok, diag::ext_empty_fnmacro_arg); - } else { - // Otherwise, emit the error. - Diag(Tok, diag::err_too_few_args_in_macro_invoc); - return 0; - } - - // Add a marker EOF token to the end of the token list for this argument. - SourceLocation EndLoc = Tok.getLocation(); - Tok.startToken(); - Tok.setKind(tok::eof); - Tok.setLocation(EndLoc); - Tok.setLength(0); - ArgTokens.push_back(Tok); - } - - return MacroArgs::create(MI, &ArgTokens[0], ArgTokens.size(),isVarargsElided); -} - -/// ComputeDATE_TIME - Compute the current time, enter it into the specified -/// scratch buffer, then return DATELoc/TIMELoc locations with the position of -/// the identifier tokens inserted. -static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, - Preprocessor &PP) { - time_t TT = time(0); - struct tm *TM = localtime(&TT); - - static const char * const Months[] = { - "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" - }; - - char TmpBuffer[100]; - sprintf(TmpBuffer, "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday, - TM->tm_year+1900); - DATELoc = PP.CreateString(TmpBuffer, strlen(TmpBuffer)); - - sprintf(TmpBuffer, "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec); - TIMELoc = PP.CreateString(TmpBuffer, strlen(TmpBuffer)); -} - -/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded -/// as a builtin macro, handle it and return the next token as 'Tok'. -void Preprocessor::ExpandBuiltinMacro(Token &Tok) { - // Figure out which token this is. - IdentifierInfo *II = Tok.getIdentifierInfo(); - assert(II && "Can't be a macro without id info!"); - - // If this is an _Pragma directive, expand it, invoke the pragma handler, then - // lex the token after it. - if (II == Ident_Pragma) - return Handle_Pragma(Tok); - - ++NumBuiltinMacroExpanded; - - char TmpBuffer[100]; - - // Set up the return result. - Tok.setIdentifierInfo(0); - Tok.clearFlag(Token::NeedsCleaning); - - if (II == Ident__LINE__) { - // __LINE__ expands to a simple numeric value. - sprintf(TmpBuffer, "%u", SourceMgr.getLogicalLineNumber(Tok.getLocation())); - unsigned Length = strlen(TmpBuffer); - Tok.setKind(tok::numeric_constant); - Tok.setLength(Length); - Tok.setLocation(CreateString(TmpBuffer, Length, Tok.getLocation())); - } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { - SourceLocation Loc = Tok.getLocation(); - if (II == Ident__BASE_FILE__) { - Diag(Tok, diag::ext_pp_base_file); - SourceLocation NextLoc = SourceMgr.getIncludeLoc(Loc); - while (NextLoc.isValid()) { - Loc = NextLoc; - NextLoc = SourceMgr.getIncludeLoc(Loc); - } - } - - // Escape this filename. Turn '\' -> '\\' '"' -> '\"' - std::string FN = SourceMgr.getSourceName(SourceMgr.getLogicalLoc(Loc)); - FN = '"' + Lexer::Stringify(FN) + '"'; - Tok.setKind(tok::string_literal); - Tok.setLength(FN.size()); - Tok.setLocation(CreateString(&FN[0], FN.size(), Tok.getLocation())); - } else if (II == Ident__DATE__) { - if (!DATELoc.isValid()) - ComputeDATE_TIME(DATELoc, TIMELoc, *this); - Tok.setKind(tok::string_literal); - Tok.setLength(strlen("\"Mmm dd yyyy\"")); - Tok.setLocation(SourceMgr.getInstantiationLoc(DATELoc, Tok.getLocation())); - } else if (II == Ident__TIME__) { - if (!TIMELoc.isValid()) - ComputeDATE_TIME(DATELoc, TIMELoc, *this); - Tok.setKind(tok::string_literal); - Tok.setLength(strlen("\"hh:mm:ss\"")); - Tok.setLocation(SourceMgr.getInstantiationLoc(TIMELoc, Tok.getLocation())); - } else if (II == Ident__INCLUDE_LEVEL__) { - Diag(Tok, diag::ext_pp_include_level); - - // Compute the include depth of this token. - unsigned Depth = 0; - SourceLocation Loc = SourceMgr.getIncludeLoc(Tok.getLocation()); - for (; Loc.isValid(); ++Depth) - Loc = SourceMgr.getIncludeLoc(Loc); - - // __INCLUDE_LEVEL__ expands to a simple numeric value. - sprintf(TmpBuffer, "%u", Depth); - unsigned Length = strlen(TmpBuffer); - Tok.setKind(tok::numeric_constant); - Tok.setLength(Length); - Tok.setLocation(CreateString(TmpBuffer, Length, Tok.getLocation())); - } else if (II == Ident__TIMESTAMP__) { - // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be - // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. - Diag(Tok, diag::ext_pp_timestamp); - - // Get the file that we are lexing out of. If we're currently lexing from - // a macro, dig into the include stack. - const FileEntry *CurFile = 0; - Lexer *TheLexer = getCurrentFileLexer(); - - if (TheLexer) - CurFile = SourceMgr.getFileEntryForLoc(TheLexer->getFileLoc()); - - // If this file is older than the file it depends on, emit a diagnostic. - const char *Result; - if (CurFile) { - time_t TT = CurFile->getModificationTime(); - struct tm *TM = localtime(&TT); - Result = asctime(TM); - } else { - Result = "??? ??? ?? ??:??:?? ????\n"; - } - TmpBuffer[0] = '"'; - strcpy(TmpBuffer+1, Result); - unsigned Len = strlen(TmpBuffer); - TmpBuffer[Len-1] = '"'; // Replace the newline with a quote. - Tok.setKind(tok::string_literal); - Tok.setLength(Len); - Tok.setLocation(CreateString(TmpBuffer, Len, Tok.getLocation())); - } else { - assert(0 && "Unknown identifier!"); - } -} diff --git a/clang/Lex/Pragma.cpp b/clang/Lex/Pragma.cpp deleted file mode 100644 index 08ad1cf1d2f..00000000000 --- a/clang/Lex/Pragma.cpp +++ /dev/null @@ -1,386 +0,0 @@ -//===--- Pragma.cpp - Pragma registration and handling --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the PragmaHandler/PragmaTable interfaces and implements -// pragma related methods of the Preprocessor class. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Pragma.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallVector.h" -using namespace clang; - -// Out-of-line destructor to provide a home for the class. -PragmaHandler::~PragmaHandler() { -} - -//===----------------------------------------------------------------------===// -// PragmaNamespace Implementation. -//===----------------------------------------------------------------------===// - - -PragmaNamespace::~PragmaNamespace() { - for (unsigned i = 0, e = Handlers.size(); i != e; ++i) - delete Handlers[i]; -} - -/// FindHandler - Check to see if there is already a handler for the -/// specified name. If not, return the handler for the null identifier if it -/// exists, otherwise return null. If IgnoreNull is true (the default) then -/// the null handler isn't returned on failure to match. -PragmaHandler *PragmaNamespace::FindHandler(const IdentifierInfo *Name, - bool IgnoreNull) const { - PragmaHandler *NullHandler = 0; - for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - if (Handlers[i]->getName() == Name) - return Handlers[i]; - - if (Handlers[i]->getName() == 0) - NullHandler = Handlers[i]; - } - return IgnoreNull ? 0 : NullHandler; -} - -void PragmaNamespace::HandlePragma(Preprocessor &PP, Token &Tok) { - // Read the 'namespace' that the directive is in, e.g. STDC. Do not macro - // expand it, the user can have a STDC #define, that should not affect this. - PP.LexUnexpandedToken(Tok); - - // Get the handler for this token. If there is no handler, ignore the pragma. - PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false); - if (Handler == 0) return; - - // Otherwise, pass it down. - Handler->HandlePragma(PP, Tok); -} - -//===----------------------------------------------------------------------===// -// Preprocessor Pragma Directive Handling. -//===----------------------------------------------------------------------===// - -/// HandlePragmaDirective - The "#pragma" directive has been parsed. Lex the -/// rest of the pragma, passing it to the registered pragma handlers. -void Preprocessor::HandlePragmaDirective() { - ++NumPragma; - - // Invoke the first level of pragma handlers which reads the namespace id. - Token Tok; - PragmaHandlers->HandlePragma(*this, Tok); - - // If the pragma handler didn't read the rest of the line, consume it now. - if (CurLexer->ParsingPreprocessorDirective) - DiscardUntilEndOfDirective(); -} - -/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then -/// return the first token after the directive. The _Pragma token has just -/// been read into 'Tok'. -void Preprocessor::Handle_Pragma(Token &Tok) { - // Remember the pragma token location. - SourceLocation PragmaLoc = Tok.getLocation(); - - // Read the '('. - Lex(Tok); - if (Tok.isNot(tok::l_paren)) - return Diag(PragmaLoc, diag::err__Pragma_malformed); - - // Read the '"..."'. - Lex(Tok); - if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) - return Diag(PragmaLoc, diag::err__Pragma_malformed); - - // Remember the string. - std::string StrVal = getSpelling(Tok); - SourceLocation StrLoc = Tok.getLocation(); - - // Read the ')'. - Lex(Tok); - if (Tok.isNot(tok::r_paren)) - return Diag(PragmaLoc, diag::err__Pragma_malformed); - - // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1. - if (StrVal[0] == 'L') // Remove L prefix. - StrVal.erase(StrVal.begin()); - assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && - "Invalid string token!"); - - // Remove the front quote, replacing it with a space, so that the pragma - // contents appear to have a space before them. - StrVal[0] = ' '; - - // Replace the terminating quote with a \n\0. - StrVal[StrVal.size()-1] = '\n'; - StrVal += '\0'; - - // Remove escaped quotes and escapes. - for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) { - if (StrVal[i] == '\\' && - (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) { - // \\ -> '\' and \" -> '"'. - StrVal.erase(StrVal.begin()+i); - --e; - } - } - - // Plop the string (including the newline and trailing null) into a buffer - // where we can lex it. - SourceLocation TokLoc = CreateString(&StrVal[0], StrVal.size(), StrLoc); - const char *StrData = SourceMgr.getCharacterData(TokLoc); - - // Make and enter a lexer object so that we lex and expand the tokens just - // like any others. - Lexer *TL = new Lexer(TokLoc, *this, - StrData, StrData+StrVal.size()-1 /* no null */); - - // Ensure that the lexer thinks it is inside a directive, so that end \n will - // return an EOM token. - TL->ParsingPreprocessorDirective = true; - - // This lexer really is for _Pragma. - TL->Is_PragmaLexer = true; - - EnterSourceFileWithLexer(TL, 0); - - // With everything set up, lex this as a #pragma directive. - HandlePragmaDirective(); - - // Finally, return whatever came after the pragma directive. - return Lex(Tok); -} - - - -/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'. -/// -void Preprocessor::HandlePragmaOnce(Token &OnceTok) { - if (isInPrimaryFile()) { - Diag(OnceTok, diag::pp_pragma_once_in_main_file); - return; - } - - // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. - SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc(); - - // Mark the file as a once-only file now. - HeaderInfo.MarkFileIncludeOnce(SourceMgr.getFileEntryForLoc(FileLoc)); -} - -void Preprocessor::HandlePragmaMark() { - assert(CurLexer && "No current lexer?"); - CurLexer->ReadToEndOfLine(); -} - - -/// HandlePragmaPoison - Handle #pragma GCC poison. PoisonTok is the 'poison'. -/// -void Preprocessor::HandlePragmaPoison(Token &PoisonTok) { - Token Tok; - - while (1) { - // Read the next token to poison. While doing this, pretend that we are - // skipping while reading the identifier to poison. - // This avoids errors on code like: - // #pragma GCC poison X - // #pragma GCC poison X - if (CurLexer) CurLexer->LexingRawMode = true; - LexUnexpandedToken(Tok); - if (CurLexer) CurLexer->LexingRawMode = false; - - // If we reached the end of line, we're done. - if (Tok.is(tok::eom)) return; - - // Can only poison identifiers. - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_pp_invalid_poison); - return; - } - - // Look up the identifier info for the token. We disabled identifier lookup - // by saying we're skipping contents, so we need to do this manually. - IdentifierInfo *II = LookUpIdentifierInfo(Tok); - - // Already poisoned. - if (II->isPoisoned()) continue; - - // If this is a macro identifier, emit a warning. - if (II->hasMacroDefinition()) - Diag(Tok, diag::pp_poisoning_existing_macro); - - // Finally, poison it! - II->setIsPoisoned(); - } -} - -/// HandlePragmaSystemHeader - Implement #pragma GCC system_header. We know -/// that the whole directive has been parsed. -void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { - if (isInPrimaryFile()) { - Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file); - return; - } - - // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. - Lexer *TheLexer = getCurrentFileLexer(); - - // Mark the file as a system header. - const FileEntry *File = SourceMgr.getFileEntryForLoc(TheLexer->getFileLoc()); - HeaderInfo.MarkFileSystemHeader(File); - - // Notify the client, if desired, that we are in a new source file. - if (Callbacks) - Callbacks->FileChanged(TheLexer->getSourceLocation(TheLexer->BufferPtr), - PPCallbacks::SystemHeaderPragma, - DirectoryLookup::SystemHeaderDir); -} - -/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah. -/// -void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { - Token FilenameTok; - CurLexer->LexIncludeFilename(FilenameTok); - - // If the token kind is EOM, the error has already been diagnosed. - if (FilenameTok.is(tok::eom)) - return; - - // Reserve a buffer to get the spelling. - llvm::SmallVector FilenameBuffer; - FilenameBuffer.resize(FilenameTok.getLength()); - - const char *FilenameStart = &FilenameBuffer[0]; - unsigned Len = getSpelling(FilenameTok, FilenameStart); - const char *FilenameEnd = FilenameStart+Len; - bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), - FilenameStart, FilenameEnd); - // If GetIncludeFilenameSpelling set the start ptr to null, there was an - // error. - if (FilenameStart == 0) - return; - - // Search include directories for this file. - const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(FilenameStart, FilenameEnd, - isAngled, 0, CurDir); - if (File == 0) - return Diag(FilenameTok, diag::err_pp_file_not_found, - std::string(FilenameStart, FilenameEnd)); - - SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc(); - const FileEntry *CurFile = SourceMgr.getFileEntryForLoc(FileLoc); - - // If this file is older than the file it depends on, emit a diagnostic. - if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) { - // Lex tokens at the end of the message and include them in the message. - std::string Message; - Lex(DependencyTok); - while (DependencyTok.isNot(tok::eom)) { - Message += getSpelling(DependencyTok) + " "; - Lex(DependencyTok); - } - - Message.erase(Message.end()-1); - Diag(FilenameTok, diag::pp_out_of_date_dependency, Message); - } -} - - -/// AddPragmaHandler - Add the specified pragma handler to the preprocessor. -/// If 'Namespace' is non-null, then it is a token required to exist on the -/// pragma line before the pragma string starts, e.g. "STDC" or "GCC". -void Preprocessor::AddPragmaHandler(const char *Namespace, - PragmaHandler *Handler) { - PragmaNamespace *InsertNS = PragmaHandlers; - - // If this is specified to be in a namespace, step down into it. - if (Namespace) { - IdentifierInfo *NSID = getIdentifierInfo(Namespace); - - // If there is already a pragma handler with the name of this namespace, - // we either have an error (directive with the same name as a namespace) or - // we already have the namespace to insert into. - if (PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID)) { - InsertNS = Existing->getIfNamespace(); - assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma" - " handler with the same name!"); - } else { - // Otherwise, this namespace doesn't exist yet, create and insert the - // handler for it. - InsertNS = new PragmaNamespace(NSID); - PragmaHandlers->AddPragma(InsertNS); - } - } - - // Check to make sure we don't already have a pragma for this identifier. - assert(!InsertNS->FindHandler(Handler->getName()) && - "Pragma handler already exists for this identifier!"); - InsertNS->AddPragma(Handler); -} - -namespace { -/// PragmaOnceHandler - "#pragma once" marks the file as atomically included. -struct PragmaOnceHandler : public PragmaHandler { - PragmaOnceHandler(const IdentifierInfo *OnceID) : PragmaHandler(OnceID) {} - virtual void HandlePragma(Preprocessor &PP, Token &OnceTok) { - PP.CheckEndOfDirective("#pragma once"); - PP.HandlePragmaOnce(OnceTok); - } -}; - -/// PragmaMarkHandler - "#pragma mark ..." is ignored by the compiler, and the -/// rest of the line is not lexed. -struct PragmaMarkHandler : public PragmaHandler { - PragmaMarkHandler(const IdentifierInfo *MarkID) : PragmaHandler(MarkID) {} - virtual void HandlePragma(Preprocessor &PP, Token &MarkTok) { - PP.HandlePragmaMark(); - } -}; - -/// PragmaPoisonHandler - "#pragma poison x" marks x as not usable. -struct PragmaPoisonHandler : public PragmaHandler { - PragmaPoisonHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} - virtual void HandlePragma(Preprocessor &PP, Token &PoisonTok) { - PP.HandlePragmaPoison(PoisonTok); - } -}; - -/// PragmaSystemHeaderHandler - "#pragma system_header" marks the current file -/// as a system header, which silences warnings in it. -struct PragmaSystemHeaderHandler : public PragmaHandler { - PragmaSystemHeaderHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} - virtual void HandlePragma(Preprocessor &PP, Token &SHToken) { - PP.HandlePragmaSystemHeader(SHToken); - PP.CheckEndOfDirective("#pragma"); - } -}; -struct PragmaDependencyHandler : public PragmaHandler { - PragmaDependencyHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} - virtual void HandlePragma(Preprocessor &PP, Token &DepToken) { - PP.HandlePragmaDependency(DepToken); - } -}; -} // end anonymous namespace - - -/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: -/// #pragma GCC poison/system_header/dependency and #pragma once. -void Preprocessor::RegisterBuiltinPragmas() { - AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once"))); - AddPragmaHandler(0, new PragmaMarkHandler(getIdentifierInfo("mark"))); - AddPragmaHandler("GCC", new PragmaPoisonHandler(getIdentifierInfo("poison"))); - AddPragmaHandler("GCC", new PragmaSystemHeaderHandler( - getIdentifierInfo("system_header"))); - AddPragmaHandler("GCC", new PragmaDependencyHandler( - getIdentifierInfo("dependency"))); -} diff --git a/clang/Lex/Preprocessor.cpp b/clang/Lex/Preprocessor.cpp deleted file mode 100644 index 86156a07728..00000000000 --- a/clang/Lex/Preprocessor.cpp +++ /dev/null @@ -1,560 +0,0 @@ -//===--- Preprocess.cpp - C Language Family Preprocessor Implementation ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Preprocessor interface. -// -//===----------------------------------------------------------------------===// -// -// Options to support: -// -H - Print the name of each header file used. -// -d[MDNI] - Dump various things. -// -fworking-directory - #line's with preprocessor's working dir. -// -fpreprocessed -// -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD -// -W* -// -w -// -// Messages to emit: -// "Multiple include guards may be useful for:\n" -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/Pragma.h" -#include "clang/Lex/ScratchBuffer.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Streams.h" -#include -using namespace clang; - -//===----------------------------------------------------------------------===// - -Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, - TargetInfo &target, SourceManager &SM, - HeaderSearch &Headers) - : Diags(diags), Features(opts), Target(target), FileMgr(Headers.getFileMgr()), - SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts), - CurLexer(0), CurDirLookup(0), CurTokenLexer(0), Callbacks(0) { - ScratchBuf = new ScratchBuffer(SourceMgr); - - // Clear stats. - NumDirectives = NumDefined = NumUndefined = NumPragma = 0; - NumIf = NumElse = NumEndif = 0; - NumEnteredSourceFiles = 0; - NumMacroExpanded = NumFnMacroExpanded = NumBuiltinMacroExpanded = 0; - NumFastMacroExpanded = NumTokenPaste = NumFastTokenPaste = 0; - MaxIncludeStackDepth = 0; - NumSkipped = 0; - - // Default to discarding comments. - KeepComments = false; - KeepMacroComments = false; - - // Macro expansion is enabled. - DisableMacroExpansion = false; - InMacroArgs = false; - NumCachedTokenLexers = 0; - - // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. - // This gets unpoisoned where it is allowed. - (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); - - Predefines = 0; - - // Initialize the pragma handlers. - PragmaHandlers = new PragmaNamespace(0); - RegisterBuiltinPragmas(); - - // Initialize builtin macros like __LINE__ and friends. - RegisterBuiltinMacros(); -} - -Preprocessor::~Preprocessor() { - // Free any active lexers. - delete CurLexer; - - while (!IncludeMacroStack.empty()) { - delete IncludeMacroStack.back().TheLexer; - delete IncludeMacroStack.back().TheTokenLexer; - IncludeMacroStack.pop_back(); - } - - // Free any macro definitions. - for (llvm::DenseMap::iterator I = - Macros.begin(), E = Macros.end(); I != E; ++I) { - // Free the macro definition. - delete I->second; - I->second = 0; - I->first->setHasMacroDefinition(false); - } - - // Free any cached macro expanders. - for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) - delete TokenLexerCache[i]; - - // Release pragma information. - delete PragmaHandlers; - - // Delete the scratch buffer info. - delete ScratchBuf; - - delete Callbacks; -} - -/// Diag - Forwarding function for diagnostics. This emits a diagnostic at -/// the specified Token's location, translating the token's start -/// position in the current buffer into a SourcePosition object for rendering. -void Preprocessor::Diag(SourceLocation Loc, unsigned DiagID) { - Diags.Report(getFullLoc(Loc), DiagID); -} - -void Preprocessor::Diag(SourceLocation Loc, unsigned DiagID, - const std::string &Msg) { - Diags.Report(getFullLoc(Loc), DiagID, &Msg, 1); -} - -void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { - llvm::cerr << tok::getTokenName(Tok.getKind()) << " '" - << getSpelling(Tok) << "'"; - - if (!DumpFlags) return; - - llvm::cerr << "\t"; - if (Tok.isAtStartOfLine()) - llvm::cerr << " [StartOfLine]"; - if (Tok.hasLeadingSpace()) - llvm::cerr << " [LeadingSpace]"; - if (Tok.isExpandDisabled()) - llvm::cerr << " [ExpandDisabled]"; - if (Tok.needsCleaning()) { - const char *Start = SourceMgr.getCharacterData(Tok.getLocation()); - llvm::cerr << " [UnClean='" << std::string(Start, Start+Tok.getLength()) - << "']"; - } - - llvm::cerr << "\tLoc=<"; - DumpLocation(Tok.getLocation()); - llvm::cerr << ">"; -} - -void Preprocessor::DumpLocation(SourceLocation Loc) const { - SourceLocation LogLoc = SourceMgr.getLogicalLoc(Loc); - llvm::cerr << SourceMgr.getSourceName(LogLoc) << ':' - << SourceMgr.getLineNumber(LogLoc) << ':' - << SourceMgr.getLineNumber(LogLoc); - - SourceLocation PhysLoc = SourceMgr.getPhysicalLoc(Loc); - if (PhysLoc != LogLoc) { - llvm::cerr << " "; - } -} - -void Preprocessor::DumpMacro(const MacroInfo &MI) const { - llvm::cerr << "MACRO: "; - for (unsigned i = 0, e = MI.getNumTokens(); i != e; ++i) { - DumpToken(MI.getReplacementToken(i)); - llvm::cerr << " "; - } - llvm::cerr << "\n"; -} - -void Preprocessor::PrintStats() { - llvm::cerr << "\n*** Preprocessor Stats:\n"; - llvm::cerr << NumDirectives << " directives found:\n"; - llvm::cerr << " " << NumDefined << " #define.\n"; - llvm::cerr << " " << NumUndefined << " #undef.\n"; - llvm::cerr << " #include/#include_next/#import:\n"; - llvm::cerr << " " << NumEnteredSourceFiles << " source files entered.\n"; - llvm::cerr << " " << MaxIncludeStackDepth << " max include stack depth\n"; - llvm::cerr << " " << NumIf << " #if/#ifndef/#ifdef.\n"; - llvm::cerr << " " << NumElse << " #else/#elif.\n"; - llvm::cerr << " " << NumEndif << " #endif.\n"; - llvm::cerr << " " << NumPragma << " #pragma.\n"; - llvm::cerr << NumSkipped << " #if/#ifndef#ifdef regions skipped\n"; - - llvm::cerr << NumMacroExpanded << "/" << NumFnMacroExpanded << "/" - << NumBuiltinMacroExpanded << " obj/fn/builtin macros expanded, " - << NumFastMacroExpanded << " on the fast path.\n"; - llvm::cerr << (NumFastTokenPaste+NumTokenPaste) - << " token paste (##) operations performed, " - << NumFastTokenPaste << " on the fast path.\n"; -} - -//===----------------------------------------------------------------------===// -// Token Spelling -//===----------------------------------------------------------------------===// - - -/// getSpelling() - Return the 'spelling' of this token. The spelling of a -/// token are the characters used to represent the token in the source file -/// after trigraph expansion and escaped-newline folding. In particular, this -/// wants to get the true, uncanonicalized, spelling of things like digraphs -/// UCNs, etc. -std::string Preprocessor::getSpelling(const Token &Tok) const { - assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); - - // If this token contains nothing interesting, return it directly. - const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation()); - if (!Tok.needsCleaning()) - return std::string(TokStart, TokStart+Tok.getLength()); - - std::string Result; - Result.reserve(Tok.getLength()); - - // Otherwise, hard case, relex the characters into the string. - for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength(); - Ptr != End; ) { - unsigned CharSize; - Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features)); - Ptr += CharSize; - } - assert(Result.size() != unsigned(Tok.getLength()) && - "NeedsCleaning flag set on something that didn't need cleaning!"); - return Result; -} - -/// getSpelling - This method is used to get the spelling of a token into a -/// preallocated buffer, instead of as an std::string. The caller is required -/// to allocate enough space for the token, which is guaranteed to be at least -/// Tok.getLength() bytes long. The actual length of the token is returned. -/// -/// Note that this method may do two possible things: it may either fill in -/// the buffer specified with characters, or it may *change the input pointer* -/// to point to a constant buffer with the data already in it (avoiding a -/// copy). The caller is not allowed to modify the returned buffer pointer -/// if an internal buffer is returned. -unsigned Preprocessor::getSpelling(const Token &Tok, - const char *&Buffer) const { - assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); - - // If this token is an identifier, just return the string from the identifier - // table, which is very quick. - if (const IdentifierInfo *II = Tok.getIdentifierInfo()) { - Buffer = II->getName(); - - // Return the length of the token. If the token needed cleaning, don't - // include the size of the newlines or trigraphs in it. - if (!Tok.needsCleaning()) - return Tok.getLength(); - else - return strlen(Buffer); - } - - // Otherwise, compute the start of the token in the input lexer buffer. - const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation()); - - // If this token contains nothing interesting, return it directly. - if (!Tok.needsCleaning()) { - Buffer = TokStart; - return Tok.getLength(); - } - // Otherwise, hard case, relex the characters into the string. - char *OutBuf = const_cast(Buffer); - for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength(); - Ptr != End; ) { - unsigned CharSize; - *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features); - Ptr += CharSize; - } - assert(unsigned(OutBuf-Buffer) != Tok.getLength() && - "NeedsCleaning flag set on something that didn't need cleaning!"); - - return OutBuf-Buffer; -} - - -/// CreateString - Plop the specified string into a scratch buffer and return a -/// location for it. If specified, the source location provides a source -/// location for the token. -SourceLocation Preprocessor:: -CreateString(const char *Buf, unsigned Len, SourceLocation SLoc) { - if (SLoc.isValid()) - return ScratchBuf->getToken(Buf, Len, SLoc); - return ScratchBuf->getToken(Buf, Len); -} - - -/// AdvanceToTokenCharacter - Given a location that specifies the start of a -/// token, return a new location that specifies a character within the token. -SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, - unsigned CharNo) { - // If they request the first char of the token, we're trivially done. If this - // is a macro expansion, it doesn't make sense to point to a character within - // the instantiation point (the name). We could point to the source - // character, but without also pointing to instantiation info, this is - // confusing. - if (CharNo == 0 || TokStart.isMacroID()) return TokStart; - - // Figure out how many physical characters away the specified logical - // character is. This needs to take into consideration newlines and - // trigraphs. - const char *TokPtr = SourceMgr.getCharacterData(TokStart); - unsigned PhysOffset = 0; - - // The usual case is that tokens don't contain anything interesting. Skip - // over the uninteresting characters. If a token only consists of simple - // chars, this method is extremely fast. - while (CharNo && Lexer::isObviouslySimpleCharacter(*TokPtr)) - ++TokPtr, --CharNo, ++PhysOffset; - - // If we have a character that may be a trigraph or escaped newline, create a - // lexer to parse it correctly. - if (CharNo != 0) { - // Create a lexer starting at this token position. - Lexer TheLexer(TokStart, *this, TokPtr); - Token Tok; - // Skip over characters the remaining characters. - const char *TokStartPtr = TokPtr; - for (; CharNo; --CharNo) - TheLexer.getAndAdvanceChar(TokPtr, Tok); - - PhysOffset += TokPtr-TokStartPtr; - } - - return TokStart.getFileLocWithOffset(PhysOffset); -} - - -//===----------------------------------------------------------------------===// -// Preprocessor Initialization Methods -//===----------------------------------------------------------------------===// - -// Append a #define line to Buf for Macro. Macro should be of the form XXX, -// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit -// "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(std::vector &Buf, const char *Macro, - const char *Command = "#define ") { - Buf.insert(Buf.end(), Command, Command+strlen(Command)); - if (const char *Equal = strchr(Macro, '=')) { - // Turn the = into ' '. - Buf.insert(Buf.end(), Macro, Equal); - Buf.push_back(' '); - Buf.insert(Buf.end(), Equal+1, Equal+strlen(Equal)); - } else { - // Push "macroname 1". - Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); - Buf.push_back(' '); - Buf.push_back('1'); - } - Buf.push_back('\n'); -} - - -static void InitializePredefinedMacros(Preprocessor &PP, - std::vector &Buf) { - // FIXME: Implement magic like cpp_init_builtins for things like __STDC__ - // and __DATE__ etc. -#if 0 - /* __STDC__ has the value 1 under normal circumstances. - However, if (a) we are in a system header, (b) the option - stdc_0_in_system_headers is true (set by target config), and - (c) we are not in strictly conforming mode, then it has the - value 0. (b) and (c) are already checked in cpp_init_builtins. */ - //case BT_STDC: - if (cpp_in_system_header (pfile)) - number = 0; - else - number = 1; - break; -#endif - // These should all be defined in the preprocessor according to the - // current language configuration. - DefineBuiltinMacro(Buf, "__STDC__=1"); - //DefineBuiltinMacro(Buf, "__ASSEMBLER__=1"); - if (PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus) - DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L"); - else if (0) // STDC94 ? - DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L"); - - DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1"); - if (PP.getLangOptions().ObjC1) - DefineBuiltinMacro(Buf, "__OBJC__=1"); - if (PP.getLangOptions().ObjC2) - DefineBuiltinMacro(Buf, "__OBJC2__=1"); - - // Add __builtin_va_list typedef. - { - const char *VAList = PP.getTargetInfo().getVAListDeclaration(); - Buf.insert(Buf.end(), VAList, VAList+strlen(VAList)); - Buf.push_back('\n'); - } - - // Get the target #defines. - PP.getTargetInfo().getTargetDefines(Buf); - - // Compiler set macros. - DefineBuiltinMacro(Buf, "__APPLE_CC__=5250"); - DefineBuiltinMacro(Buf, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1050"); - DefineBuiltinMacro(Buf, "__GNUC_MINOR__=0"); - DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1"); - DefineBuiltinMacro(Buf, "__GNUC__=4"); - DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002"); - DefineBuiltinMacro(Buf, "__VERSION__=\"4.0.1 (Apple Computer, Inc. " - "build 5250)\""); - - // Build configuration options. - DefineBuiltinMacro(Buf, "__DYNAMIC__=1"); - DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0"); - DefineBuiltinMacro(Buf, "__NO_INLINE__=1"); - DefineBuiltinMacro(Buf, "__PIC__=1"); - - - if (PP.getLangOptions().CPlusPlus) { - DefineBuiltinMacro(Buf, "__DEPRECATED=1"); - DefineBuiltinMacro(Buf, "__EXCEPTIONS=1"); - DefineBuiltinMacro(Buf, "__GNUG__=4"); - DefineBuiltinMacro(Buf, "__GXX_WEAK__=1"); - DefineBuiltinMacro(Buf, "__cplusplus=1"); - DefineBuiltinMacro(Buf, "__private_extern__=extern"); - } - if (PP.getLangOptions().Microsoft) { - DefineBuiltinMacro(Buf, "__stdcall="); - DefineBuiltinMacro(Buf, "__cdecl="); - DefineBuiltinMacro(Buf, "_cdecl="); - DefineBuiltinMacro(Buf, "__ptr64="); - DefineBuiltinMacro(Buf, "__w64="); - DefineBuiltinMacro(Buf, "__forceinline="); - DefineBuiltinMacro(Buf, "__int8=char"); - DefineBuiltinMacro(Buf, "__int16=short"); - DefineBuiltinMacro(Buf, "__int32=int"); - DefineBuiltinMacro(Buf, "__int64=long long"); - DefineBuiltinMacro(Buf, "__declspec(X)="); - } - // FIXME: Should emit a #line directive here. -} - - -/// EnterMainSourceFile - Enter the specified FileID as the main source file, -/// which implicitly adds the builtin defines etc. -void Preprocessor::EnterMainSourceFile() { - - unsigned MainFileID = SourceMgr.getMainFileID(); - - // Enter the main file source buffer. - EnterSourceFile(MainFileID, 0); - - // Tell the header info that the main file was entered. If the file is later - // #imported, it won't be re-entered. - if (const FileEntry *FE = - SourceMgr.getFileEntryForLoc(SourceLocation::getFileLoc(MainFileID, 0))) - HeaderInfo.IncrementIncludeCount(FE); - - std::vector PrologFile; - PrologFile.reserve(4080); - - // Install things like __POWERPC__, __GNUC__, etc into the macro table. - InitializePredefinedMacros(*this, PrologFile); - - // Add on the predefines from the driver. - PrologFile.insert(PrologFile.end(), Predefines,Predefines+strlen(Predefines)); - - // Memory buffer must end with a null byte! - PrologFile.push_back(0); - - // Now that we have emitted the predefined macros, #includes, etc into - // PrologFile, preprocess it to populate the initial preprocessor state. - llvm::MemoryBuffer *SB = - llvm::MemoryBuffer::getMemBufferCopy(&PrologFile.front(),&PrologFile.back(), - ""); - assert(SB && "Cannot fail to create predefined source buffer"); - unsigned FileID = SourceMgr.createFileIDForMemBuffer(SB); - assert(FileID && "Could not create FileID for predefines?"); - - // Start parsing the predefines. - EnterSourceFile(FileID, 0); -} - - -//===----------------------------------------------------------------------===// -// Lexer Event Handling. -//===----------------------------------------------------------------------===// - -/// LookUpIdentifierInfo - Given a tok::identifier token, look up the -/// identifier information for the token and install it into the token. -IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier, - const char *BufPtr) { - assert(Identifier.is(tok::identifier) && "Not an identifier!"); - assert(Identifier.getIdentifierInfo() == 0 && "Identinfo already exists!"); - - // Look up this token, see if it is a macro, or if it is a language keyword. - IdentifierInfo *II; - if (BufPtr && !Identifier.needsCleaning()) { - // No cleaning needed, just use the characters from the lexed buffer. - II = getIdentifierInfo(BufPtr, BufPtr+Identifier.getLength()); - } else { - // Cleaning needed, alloca a buffer, clean into it, then use the buffer. - llvm::SmallVector IdentifierBuffer; - IdentifierBuffer.resize(Identifier.getLength()); - const char *TmpBuf = &IdentifierBuffer[0]; - unsigned Size = getSpelling(Identifier, TmpBuf); - II = getIdentifierInfo(TmpBuf, TmpBuf+Size); - } - Identifier.setIdentifierInfo(II); - return II; -} - - -/// HandleIdentifier - This callback is invoked when the lexer reads an -/// identifier. This callback looks up the identifier in the map and/or -/// potentially macro expands it or turns it into a named token (like 'for'). -void Preprocessor::HandleIdentifier(Token &Identifier) { - assert(Identifier.getIdentifierInfo() && - "Can't handle identifiers without identifier info!"); - - IdentifierInfo &II = *Identifier.getIdentifierInfo(); - - // If this identifier was poisoned, and if it was not produced from a macro - // expansion, emit an error. - if (II.isPoisoned() && CurLexer) { - if (&II != Ident__VA_ARGS__) // We warn about __VA_ARGS__ with poisoning. - Diag(Identifier, diag::err_pp_used_poisoned_id); - else - Diag(Identifier, diag::ext_pp_bad_vaargs_use); - } - - // If this is a macro to be expanded, do it. - if (MacroInfo *MI = getMacroInfo(&II)) { - if (!DisableMacroExpansion && !Identifier.isExpandDisabled()) { - if (MI->isEnabled()) { - if (!HandleMacroExpandedIdentifier(Identifier, MI)) - return; - } else { - // C99 6.10.3.4p2 says that a disabled macro may never again be - // expanded, even if it's in a context where it could be expanded in the - // future. - Identifier.setFlag(Token::DisableExpand); - } - } - } - - // C++ 2.11p2: If this is an alternative representation of a C++ operator, - // then we act as if it is the actual operator and not the textual - // representation of it. - if (II.isCPlusPlusOperatorKeyword()) - Identifier.setIdentifierInfo(0); - - // Change the kind of this identifier to the appropriate token kind, e.g. - // turning "for" into a keyword. - Identifier.setKind(II.getTokenID()); - - // If this is an extension token, diagnose its use. - // FIXME: tried (unsuccesfully) to shut this up when compiling with gnu99 - // For now, I'm just commenting it out (while I work on attributes). - if (II.isExtensionToken() && Features.C99) - Diag(Identifier, diag::ext_token_used); -} - diff --git a/clang/Lex/ScratchBuffer.cpp b/clang/Lex/ScratchBuffer.cpp deleted file mode 100644 index 99fbdf75654..00000000000 --- a/clang/Lex/ScratchBuffer.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the ScratchBuffer interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/ScratchBuffer.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/MemoryBuffer.h" -#include -using namespace clang; - -// ScratchBufSize - The size of each chunk of scratch memory. Slightly less -//than a page, almost certainly enough for anything. :) -static const unsigned ScratchBufSize = 4060; - -ScratchBuffer::ScratchBuffer(SourceManager &SM) : SourceMgr(SM), CurBuffer(0) { - // Set BytesUsed so that the first call to getToken will require an alloc. - BytesUsed = ScratchBufSize; - FileID = 0; -} - -/// getToken - Splat the specified text into a temporary MemoryBuffer and -/// return a SourceLocation that refers to the token. This is just like the -/// method below, but returns a location that indicates the physloc of the -/// token. -SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len) { - if (BytesUsed+Len > ScratchBufSize) - AllocScratchBuffer(Len); - - // Copy the token data into the buffer. - memcpy(CurBuffer+BytesUsed, Buf, Len); - - // Remember that we used these bytes. - BytesUsed += Len; - - assert(BytesUsed-Len < (1 << SourceLocation::FilePosBits) && - "Out of range file position!"); - - return SourceLocation::getFileLoc(FileID, BytesUsed-Len); -} - - -/// getToken - Splat the specified text into a temporary MemoryBuffer and -/// return a SourceLocation that refers to the token. The SourceLoc value -/// gives a virtual location that the token will appear to be from. -SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len, - SourceLocation SourceLoc) { - // Map the physloc to the specified sourceloc. - return SourceMgr.getInstantiationLoc(getToken(Buf, Len), SourceLoc); -} - -void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) { - // Only pay attention to the requested length if it is larger than our default - // page size. If it is, we allocate an entire chunk for it. This is to - // support gigantic tokens, which almost certainly won't happen. :) - if (RequestLen < ScratchBufSize) - RequestLen = ScratchBufSize; - - llvm::MemoryBuffer *Buf = - llvm::MemoryBuffer::getNewMemBuffer(RequestLen, ""); - FileID = SourceMgr.createFileIDForMemBuffer(Buf); - CurBuffer = const_cast(Buf->getBufferStart()); - BytesUsed = 0; -} diff --git a/clang/Lex/TokenLexer.cpp b/clang/Lex/TokenLexer.cpp deleted file mode 100644 index fc8cfd715c4..00000000000 --- a/clang/Lex/TokenLexer.cpp +++ /dev/null @@ -1,488 +0,0 @@ -//===--- TokenLexer.cpp - Lex from a token stream -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the TokenLexer interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Lex/TokenLexer.h" -#include "MacroArgs.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/SmallVector.h" -using namespace clang; - - -/// Create a TokenLexer for the specified macro with the specified actual -/// arguments. Note that this ctor takes ownership of the ActualArgs pointer. -void TokenLexer::Init(Token &Tok, MacroArgs *Actuals) { - // If the client is reusing a TokenLexer, make sure to free any memory - // associated with it. - destroy(); - - Macro = PP.getMacroInfo(Tok.getIdentifierInfo()); - ActualArgs = Actuals; - CurToken = 0; - InstantiateLoc = Tok.getLocation(); - AtStartOfLine = Tok.isAtStartOfLine(); - HasLeadingSpace = Tok.hasLeadingSpace(); - Tokens = &*Macro->tokens_begin(); - OwnsTokens = false; - DisableMacroExpansion = false; - NumTokens = Macro->tokens_end()-Macro->tokens_begin(); - - // If this is a function-like macro, expand the arguments and change - // Tokens to point to the expanded tokens. - if (Macro->isFunctionLike() && Macro->getNumArgs()) - ExpandFunctionArguments(); - - // Mark the macro as currently disabled, so that it is not recursively - // expanded. The macro must be disabled only after argument pre-expansion of - // function-like macro arguments occurs. - Macro->DisableMacro(); -} - - - -/// Create a TokenLexer for the specified token stream. This does not -/// take ownership of the specified token vector. -void TokenLexer::Init(const Token *TokArray, unsigned NumToks, - bool disableMacroExpansion, bool ownsTokens) { - // If the client is reusing a TokenLexer, make sure to free any memory - // associated with it. - destroy(); - - Macro = 0; - ActualArgs = 0; - Tokens = TokArray; - OwnsTokens = ownsTokens; - DisableMacroExpansion = disableMacroExpansion; - NumTokens = NumToks; - CurToken = 0; - InstantiateLoc = SourceLocation(); - AtStartOfLine = false; - HasLeadingSpace = false; - - // Set HasLeadingSpace/AtStartOfLine so that the first token will be - // returned unmodified. - if (NumToks != 0) { - AtStartOfLine = TokArray[0].isAtStartOfLine(); - HasLeadingSpace = TokArray[0].hasLeadingSpace(); - } -} - - -void TokenLexer::destroy() { - // If this was a function-like macro that actually uses its arguments, delete - // the expanded tokens. - if (OwnsTokens) { - delete [] Tokens; - Tokens = 0; - } - - // TokenLexer owns its formal arguments. - if (ActualArgs) ActualArgs->destroy(); -} - -/// Expand the arguments of a function-like macro so that we can quickly -/// return preexpanded tokens from Tokens. -void TokenLexer::ExpandFunctionArguments() { - llvm::SmallVector ResultToks; - - // Loop through 'Tokens', expanding them into ResultToks. Keep - // track of whether we change anything. If not, no need to keep them. If so, - // we install the newly expanded sequence as the new 'Tokens' list. - bool MadeChange = false; - - // NextTokGetsSpace - When this is true, the next token appended to the - // output list will get a leading space, regardless of whether it had one to - // begin with or not. This is used for placemarker support. - bool NextTokGetsSpace = false; - - for (unsigned i = 0, e = NumTokens; i != e; ++i) { - // If we found the stringify operator, get the argument stringified. The - // preprocessor already verified that the following token is a macro name - // when the #define was parsed. - const Token &CurTok = Tokens[i]; - if (CurTok.is(tok::hash) || CurTok.is(tok::hashat)) { - int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo()); - assert(ArgNo != -1 && "Token following # is not an argument?"); - - Token Res; - if (CurTok.is(tok::hash)) // Stringify - Res = ActualArgs->getStringifiedArgument(ArgNo, PP); - else { - // 'charify': don't bother caching these. - Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo), - PP, true); - } - - // The stringified/charified string leading space flag gets set to match - // the #/#@ operator. - if (CurTok.hasLeadingSpace() || NextTokGetsSpace) - Res.setFlag(Token::LeadingSpace); - - ResultToks.push_back(Res); - MadeChange = true; - ++i; // Skip arg name. - NextTokGetsSpace = false; - continue; - } - - // Otherwise, if this is not an argument token, just add the token to the - // output buffer. - IdentifierInfo *II = CurTok.getIdentifierInfo(); - int ArgNo = II ? Macro->getArgumentNum(II) : -1; - if (ArgNo == -1) { - // This isn't an argument, just add it. - ResultToks.push_back(CurTok); - - if (NextTokGetsSpace) { - ResultToks.back().setFlag(Token::LeadingSpace); - NextTokGetsSpace = false; - } - continue; - } - - // An argument is expanded somehow, the result is different than the - // input. - MadeChange = true; - - // Otherwise, this is a use of the argument. Find out if there is a paste - // (##) operator before or after the argument. - bool PasteBefore = - !ResultToks.empty() && ResultToks.back().is(tok::hashhash); - bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash); - - // If it is not the LHS/RHS of a ## operator, we must pre-expand the - // argument and substitute the expanded tokens into the result. This is - // C99 6.10.3.1p1. - if (!PasteBefore && !PasteAfter) { - const Token *ResultArgToks; - - // Only preexpand the argument if it could possibly need it. This - // avoids some work in common cases. - const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo); - if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP)) - ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0]; - else - ResultArgToks = ArgTok; // Use non-preexpanded tokens. - - // If the arg token expanded into anything, append it. - if (ResultArgToks->isNot(tok::eof)) { - unsigned FirstResult = ResultToks.size(); - unsigned NumToks = MacroArgs::getArgLength(ResultArgToks); - ResultToks.append(ResultArgToks, ResultArgToks+NumToks); - - // If any tokens were substituted from the argument, the whitespace - // before the first token should match the whitespace of the arg - // identifier. - ResultToks[FirstResult].setFlagValue(Token::LeadingSpace, - CurTok.hasLeadingSpace() || - NextTokGetsSpace); - NextTokGetsSpace = false; - } else { - // If this is an empty argument, and if there was whitespace before the - // formal token, make sure the next token gets whitespace before it. - NextTokGetsSpace = CurTok.hasLeadingSpace(); - } - continue; - } - - // Okay, we have a token that is either the LHS or RHS of a paste (##) - // argument. It gets substituted as its non-pre-expanded tokens. - const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo); - unsigned NumToks = MacroArgs::getArgLength(ArgToks); - if (NumToks) { // Not an empty argument? - // If this is the GNU ", ## __VA_ARG__" extension, and we just learned - // that __VA_ARG__ expands to multiple tokens, avoid a pasting error when - // the expander trys to paste ',' with the first token of the __VA_ARG__ - // expansion. - if (PasteBefore && ResultToks.size() >= 2 && - ResultToks[ResultToks.size()-2].is(tok::comma) && - (unsigned)ArgNo == Macro->getNumArgs()-1 && - Macro->isVariadic()) { - // Remove the paste operator, report use of the extension. - PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); - ResultToks.pop_back(); - } - - ResultToks.append(ArgToks, ArgToks+NumToks); - - // If the next token was supposed to get leading whitespace, ensure it has - // it now. - if (NextTokGetsSpace) { - ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace); - NextTokGetsSpace = false; - } - continue; - } - - // If an empty argument is on the LHS or RHS of a paste, the standard (C99 - // 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We - // implement this by eating ## operators when a LHS or RHS expands to - // empty. - NextTokGetsSpace |= CurTok.hasLeadingSpace(); - if (PasteAfter) { - // Discard the argument token and skip (don't copy to the expansion - // buffer) the paste operator after it. - NextTokGetsSpace |= Tokens[i+1].hasLeadingSpace(); - ++i; - continue; - } - - // If this is on the RHS of a paste operator, we've already copied the - // paste operator to the ResultToks list. Remove it. - assert(PasteBefore && ResultToks.back().is(tok::hashhash)); - NextTokGetsSpace |= ResultToks.back().hasLeadingSpace(); - ResultToks.pop_back(); - - // If this is the __VA_ARGS__ token, and if the argument wasn't provided, - // and if the macro had at least one real argument, and if the token before - // the ## was a comma, remove the comma. - if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__ - ActualArgs->isVarargsElidedUse() && // Argument elided. - !ResultToks.empty() && ResultToks.back().is(tok::comma)) { - // Never add a space, even if the comma, ##, or arg had a space. - NextTokGetsSpace = false; - // Remove the paste operator, report use of the extension. - PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); - ResultToks.pop_back(); - } - continue; - } - - // If anything changed, install this as the new Tokens list. - if (MadeChange) { - // This is deleted in the dtor. - NumTokens = ResultToks.size(); - Token *Res = new Token[ResultToks.size()]; - if (NumTokens) - memcpy(Res, &ResultToks[0], NumTokens*sizeof(Token)); - Tokens = Res; - OwnsTokens = true; - } -} - -/// Lex - Lex and return a token from this macro stream. -/// -void TokenLexer::Lex(Token &Tok) { - // Lexing off the end of the macro, pop this macro off the expansion stack. - if (isAtEnd()) { - // If this is a macro (not a token stream), mark the macro enabled now - // that it is no longer being expanded. - if (Macro) Macro->EnableMacro(); - - // Pop this context off the preprocessors lexer stack and get the next - // token. This will delete "this" so remember the PP instance var. - Preprocessor &PPCache = PP; - if (PP.HandleEndOfTokenLexer(Tok)) - return; - - // HandleEndOfTokenLexer may not return a token. If it doesn't, lex - // whatever is next. - return PPCache.Lex(Tok); - } - - // If this is the first token of the expanded result, we inherit spacing - // properties later. - bool isFirstToken = CurToken == 0; - - // Get the next token to return. - Tok = Tokens[CurToken++]; - - // If this token is followed by a token paste (##) operator, paste the tokens! - if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) - if (PasteTokens(Tok)) { - // When handling the microsoft /##/ extension, the final token is - // returned by PasteTokens, not the pasted token. - return; - } - - // The token's current location indicate where the token was lexed from. We - // need this information to compute the spelling of the token, but any - // diagnostics for the expanded token should appear as if they came from - // InstantiationLoc. Pull this information together into a new SourceLocation - // that captures all of this. - if (InstantiateLoc.isValid()) { // Don't do this for token streams. - SourceManager &SrcMgr = PP.getSourceManager(); - Tok.setLocation(SrcMgr.getInstantiationLoc(Tok.getLocation(), - InstantiateLoc)); - } - - // If this is the first token, set the lexical properties of the token to - // match the lexical properties of the macro identifier. - if (isFirstToken) { - Tok.setFlagValue(Token::StartOfLine , AtStartOfLine); - Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); - } - - // Handle recursive expansion! - if (Tok.getIdentifierInfo() && !DisableMacroExpansion) - return PP.HandleIdentifier(Tok); - - // Otherwise, return a normal token. -} - -/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## -/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there -/// are is another ## after it, chomp it iteratively. Return the result as Tok. -/// If this returns true, the caller should immediately return the token. -bool TokenLexer::PasteTokens(Token &Tok) { - llvm::SmallVector Buffer; - do { - // Consume the ## operator. - SourceLocation PasteOpLoc = Tokens[CurToken].getLocation(); - ++CurToken; - assert(!isAtEnd() && "No token on the RHS of a paste operator!"); - - // Get the RHS token. - const Token &RHS = Tokens[CurToken]; - - bool isInvalid = false; - - // Allocate space for the result token. This is guaranteed to be enough for - // the two tokens and a null terminator. - Buffer.resize(Tok.getLength() + RHS.getLength() + 1); - - // Get the spelling of the LHS token in Buffer. - const char *BufPtr = &Buffer[0]; - unsigned LHSLen = PP.getSpelling(Tok, BufPtr); - if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer! - memcpy(&Buffer[0], BufPtr, LHSLen); - - BufPtr = &Buffer[LHSLen]; - unsigned RHSLen = PP.getSpelling(RHS, BufPtr); - if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer! - memcpy(&Buffer[LHSLen], BufPtr, RHSLen); - - // Add null terminator. - Buffer[LHSLen+RHSLen] = '\0'; - - // Trim excess space. - Buffer.resize(LHSLen+RHSLen+1); - - // Plop the pasted result (including the trailing newline and null) into a - // scratch buffer where we can lex it. - SourceLocation ResultTokLoc = PP.CreateString(&Buffer[0], Buffer.size()); - - // Lex the resultant pasted token into Result. - Token Result; - - // Avoid testing /*, as the lexer would think it is the start of a comment - // and emit an error that it is unterminated. - if (Tok.is(tok::slash) && RHS.is(tok::star)) { - isInvalid = true; - } else if (Tok.is(tok::identifier) && RHS.is(tok::identifier)) { - // Common paste case: identifier+identifier = identifier. Avoid creating - // a lexer and other overhead. - PP.IncrementPasteCounter(true); - Result.startToken(); - Result.setKind(tok::identifier); - Result.setLocation(ResultTokLoc); - Result.setLength(LHSLen+RHSLen); - } else { - PP.IncrementPasteCounter(false); - - // Make a lexer to lex this string from. - SourceManager &SourceMgr = PP.getSourceManager(); - const char *ResultStrData = SourceMgr.getCharacterData(ResultTokLoc); - - // Make a lexer object so that we lex and expand the paste result. - Lexer *TL = new Lexer(ResultTokLoc, PP, ResultStrData, - ResultStrData+LHSLen+RHSLen /*don't include null*/); - - // Lex a token in raw mode. This way it won't look up identifiers - // automatically, lexing off the end will return an eof token, and - // warnings are disabled. This returns true if the result token is the - // entire buffer. - bool IsComplete = TL->LexRawToken(Result); - - // If we got an EOF token, we didn't form even ONE token. For example, we - // did "/ ## /" to get "//". - IsComplete &= Result.isNot(tok::eof); - isInvalid = !IsComplete; - - // We're now done with the temporary lexer. - delete TL; - } - - // If pasting the two tokens didn't form a full new token, this is an error. - // This occurs with "x ## +" and other stuff. Return with Tok unmodified - // and with RHS as the next token to lex. - if (isInvalid) { - // Test for the Microsoft extension of /##/ turning into // here on the - // error path. - if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) && - RHS.is(tok::slash)) { - HandleMicrosoftCommentPaste(Tok); - return true; - } else { - // TODO: If not in assembler language mode. - PP.Diag(PasteOpLoc, diag::err_pp_bad_paste, - std::string(Buffer.begin(), Buffer.end()-1)); - return false; - } - } - - // Turn ## into 'unknown' to avoid # ## # from looking like a paste - // operator. - if (Result.is(tok::hashhash)) - Result.setKind(tok::unknown); - // FIXME: Turn __VA_ARGS__ into "not a token"? - - // Transfer properties of the LHS over the the Result. - Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine()); - Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace()); - - // Finally, replace LHS with the result, consume the RHS, and iterate. - ++CurToken; - Tok = Result; - } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)); - - // Now that we got the result token, it will be subject to expansion. Since - // token pasting re-lexes the result token in raw mode, identifier information - // isn't looked up. As such, if the result is an identifier, look up id info. - if (Tok.is(tok::identifier)) { - // Look up the identifier info for the token. We disabled identifier lookup - // by saying we're skipping contents, so we need to do this manually. - Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok)); - } - return false; -} - -/// isNextTokenLParen - If the next token lexed will pop this macro off the -/// expansion stack, return 2. If the next unexpanded token is a '(', return -/// 1, otherwise return 0. -unsigned TokenLexer::isNextTokenLParen() const { - // Out of tokens? - if (isAtEnd()) - return 2; - return Tokens[CurToken].is(tok::l_paren); -} - - -/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes -/// together to form a comment that comments out everything in the current -/// macro, other active macros, and anything left on the current physical -/// source line of the instantiated buffer. Handle this by returning the -/// first token on the next line. -void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) { - // We 'comment out' the rest of this macro by just ignoring the rest of the - // tokens that have not been lexed yet, if any. - - // Since this must be a macro, mark the macro enabled now that it is no longer - // being expanded. - assert(Macro && "Token streams can't paste comments"); - Macro->EnableMacro(); - - PP.HandleMicrosoftCommentPaste(Tok); -} diff --git a/clang/Makefile b/clang/Makefile index 10350a8eb98..7d990da0ad8 100644 --- a/clang/Makefile +++ b/clang/Makefile @@ -1,5 +1,5 @@ LEVEL = ../.. -DIRS := Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite Driver +DIRS := lib Driver include $(LEVEL)/Makefile.common diff --git a/clang/Parse/AttributeList.cpp b/clang/Parse/AttributeList.cpp deleted file mode 100644 index 0ff9447d2e6..00000000000 --- a/clang/Parse/AttributeList.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===--- AttributeList.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the AttributeList class implementation -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/AttributeList.h" -using namespace clang; - -AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, - IdentifierInfo *pName, SourceLocation pLoc, - Action::ExprTy **elist, unsigned numargs, - AttributeList *n) - : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc), - NumArgs(numargs), Next(n) { - Args = new Action::ExprTy*[numargs]; - for (unsigned i = 0; i != numargs; ++i) - Args[i] = elist[i]; -} - -AttributeList::~AttributeList() { - if (Args) { - // FIXME: before we delete the vector, we need to make sure the Expr's - // have been deleted. Since Action::ExprTy is "void", we are dependent - // on the actions module for actually freeing the memory. The specific - // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType, - // ParseField, ParseTag. Once these routines have freed the expression, - // they should zero out the Args slot (to indicate the memory has been - // freed). If any element of the vector is non-null, we should assert. - delete [] Args; - } - delete Next; -} - -AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { - const char *Str = Name->getName(); - unsigned Len = Name->getLength(); - - // Normalize the attribute name, __foo__ becomes foo. - if (Len > 4 && Str[0] == '_' && Str[1] == '_' && - Str[Len - 2] == '_' && Str[Len - 1] == '_') { - Str += 2; - Len -= 4; - } - - switch (Len) { - case 4: - if (!memcmp(Str, "weak", 4)) return AT_weak; - if (!memcmp(Str, "pure", 4)) return AT_pure; - break; - case 6: - if (!memcmp(Str, "packed", 6)) return AT_packed; - if (!memcmp(Str, "malloc", 6)) return AT_malloc; - if (!memcmp(Str, "format", 6)) return AT_format; - if (!memcmp(Str, "unused", 6)) return AT_unused; - break; - case 7: - if (!memcmp(Str, "aligned", 7)) return AT_aligned; - if (!memcmp(Str, "nothrow", 7)) return AT_nothrow; - if (!memcmp(Str, "nonnull", 7)) return AT_nonnull; - if (!memcmp(Str, "stdcall", 7)) return AT_stdcall; - break; - case 8: - if (!memcmp(Str, "annotate", 8)) return AT_annotate; - if (!memcmp(Str, "noreturn", 8)) return AT_noreturn; - if (!memcmp(Str, "noinline", 8)) return AT_noinline; - if (!memcmp(Str, "fastcall", 8)) return AT_fastcall; - break; - case 9: - if (!memcmp(Str, "dllimport", 9)) return AT_dllimport; - if (!memcmp(Str, "dllexport", 9)) return AT_dllexport; - break; - case 10: - if (!memcmp(Str, "deprecated", 10)) return AT_deprecated; - if (!memcmp(Str, "visibility", 10)) return AT_visibility; - break; - case 11: - if (!memcmp(Str, "vector_size", 11)) return AT_vector_size; - break; - case 13: - if (!memcmp(Str, "address_space", 13)) return AT_address_space; - break; - case 15: - if (!memcmp(Str, "ocu_vector_type", 15)) return AT_ocu_vector_type; - break; - case 18: - if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result; - break; - } - return UnknownAttribute; -} diff --git a/clang/Parse/DeclSpec.cpp b/clang/Parse/DeclSpec.cpp deleted file mode 100644 index 1cd350893f4..00000000000 --- a/clang/Parse/DeclSpec.cpp +++ /dev/null @@ -1,287 +0,0 @@ -//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for declaration specifiers. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/DeclSpec.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/SourceLocation.h" -using namespace clang; - -/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this -/// -unsigned DeclSpec::getParsedSpecifiers() const { - unsigned Res = 0; - if (StorageClassSpec != SCS_unspecified || - SCS_thread_specified) - Res |= PQ_StorageClassSpecifier; - - if (TypeQualifiers != TQ_unspecified) - Res |= PQ_TypeQualifier; - - if (hasTypeSpecifier()) - Res |= PQ_TypeSpecifier; - - if (FS_inline_specified) - Res |= PQ_FunctionSpecifier; - return Res; -} - -const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { - switch (S) { - default: assert(0 && "Unknown typespec!"); - case DeclSpec::SCS_unspecified: return "unspecified"; - case DeclSpec::SCS_typedef: return "typedef"; - case DeclSpec::SCS_extern: return "extern"; - case DeclSpec::SCS_static: return "static"; - case DeclSpec::SCS_auto: return "auto"; - case DeclSpec::SCS_register: return "register"; - } -} - -bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) { - PrevSpec = getSpecifierName(S); - return true; -} - -bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) { - switch (W) { - case TSW_unspecified: PrevSpec = "unspecified"; break; - case TSW_short: PrevSpec = "short"; break; - case TSW_long: PrevSpec = "long"; break; - case TSW_longlong: PrevSpec = "long long"; break; - } - return true; -} - -bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) { - switch (C) { - case TSC_unspecified: PrevSpec = "unspecified"; break; - case TSC_imaginary: PrevSpec = "imaginary"; break; - case TSC_complex: PrevSpec = "complex"; break; - } - return true; -} - - -bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) { - switch (S) { - case TSS_unspecified: PrevSpec = "unspecified"; break; - case TSS_signed: PrevSpec = "signed"; break; - case TSS_unsigned: PrevSpec = "unsigned"; break; - } - return true; -} - -const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { - switch (T) { - default: assert(0 && "Unknown typespec!"); - case DeclSpec::TST_unspecified: return "unspecified"; - case DeclSpec::TST_void: return "void"; - case DeclSpec::TST_char: return "char"; - case DeclSpec::TST_int: return "int"; - case DeclSpec::TST_float: return "float"; - case DeclSpec::TST_double: return "double"; - case DeclSpec::TST_bool: return "_Bool"; - case DeclSpec::TST_decimal32: return "_Decimal32"; - case DeclSpec::TST_decimal64: return "_Decimal64"; - case DeclSpec::TST_decimal128: return "_Decimal128"; - case DeclSpec::TST_enum: return "enum"; - case DeclSpec::TST_union: return "union"; - case DeclSpec::TST_struct: return "struct"; - case DeclSpec::TST_typedef: return "typedef"; - case DeclSpec::TST_typeofType: - case DeclSpec::TST_typeofExpr: return "typeof"; - } -} - -bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) { - PrevSpec = getSpecifierName(T); - return true; -} - -bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) { - switch (T) { - case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break; - case DeclSpec::TQ_const: PrevSpec = "const"; break; - case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break; - case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break; - } - return true; -} - -bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, - const char *&PrevSpec) { - if (StorageClassSpec != SCS_unspecified) - return BadSpecifier( (SCS)StorageClassSpec, PrevSpec); - StorageClassSpec = S; - StorageClassSpecLoc = Loc; - return false; -} - -bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, - const char *&PrevSpec) { - if (SCS_thread_specified) { - PrevSpec = "__thread"; - return true; - } - SCS_thread_specified = true; - SCS_threadLoc = Loc; - return false; -} - - -/// These methods set the specified attribute of the DeclSpec, but return true -/// and ignore the request if invalid (e.g. "extern" then "auto" is -/// specified). -bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, - const char *&PrevSpec) { - if (TypeSpecWidth != TSW_unspecified && - // Allow turning long -> long long. - (W != TSW_longlong || TypeSpecWidth != TSW_long)) - return BadSpecifier( (TSW)TypeSpecWidth, PrevSpec); - TypeSpecWidth = W; - TSWLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, - const char *&PrevSpec) { - if (TypeSpecComplex != TSC_unspecified) - return BadSpecifier( (TSC)TypeSpecComplex, PrevSpec); - TypeSpecComplex = C; - TSCLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, - const char *&PrevSpec) { - if (TypeSpecSign != TSS_unspecified) - return BadSpecifier( (TSS)TypeSpecSign, PrevSpec); - TypeSpecSign = S; - TSSLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, - const char *&PrevSpec, void *Rep) { - if (TypeSpecType != TST_unspecified) - return BadSpecifier( (TST)TypeSpecType, PrevSpec); - TypeSpecType = T; - TypeRep = Rep; - TSTLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, - const LangOptions &Lang) { - // Duplicates turn into warnings pre-C99. - if ((TypeQualifiers & T) && !Lang.C99) - return BadSpecifier(T, PrevSpec); - TypeQualifiers |= T; - - switch (T) { - default: assert(0 && "Unknown type qualifier!"); - case TQ_const: TQ_constLoc = Loc; break; - case TQ_restrict: TQ_restrictLoc = Loc; break; - case TQ_volatile: TQ_volatileLoc = Loc; break; - } - return false; -} - -bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){ - // 'inline inline' is ok. - FS_inline_specified = true; - FS_inlineLoc = Loc; - return false; -} - - -/// Finish - This does final analysis of the declspec, rejecting things like -/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or -/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, -/// DeclSpec is guaranteed self-consistent, even if an error occurred. -void DeclSpec::Finish(Diagnostic &D, SourceManager& SrcMgr, - const LangOptions &Lang) { - // Check the type specifier components first. - - // signed/unsigned are only valid with int/char. - if (TypeSpecSign != TSS_unspecified) { - if (TypeSpecType == TST_unspecified) - TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. - else if (TypeSpecType != TST_int && TypeSpecType != TST_char) { - Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec, - getSpecifierName( (TST)TypeSpecType)); - // signed double -> double. - TypeSpecSign = TSS_unspecified; - } - } - - // Validate the width of the type. - switch (TypeSpecWidth) { - case TSW_unspecified: break; - case TSW_short: // short int - case TSW_longlong: // long long int - if (TypeSpecType == TST_unspecified) - TypeSpecType = TST_int; // short -> short int, long long -> long long int. - else if (TypeSpecType != TST_int) { - Diag(D, TSWLoc, SrcMgr, - TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec - : diag::err_invalid_longlong_spec, - getSpecifierName( (TST)TypeSpecType)); - TypeSpecType = TST_int; - } - break; - case TSW_long: // long double, long int - if (TypeSpecType == TST_unspecified) - TypeSpecType = TST_int; // long -> long int. - else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { - Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec, - getSpecifierName( (TST)TypeSpecType)); - TypeSpecType = TST_int; - } - break; - } - - // TODO: if the implementation does not implement _Complex or _Imaginary, - // disallow their use. Need information about the backend. - if (TypeSpecComplex != TSC_unspecified) { - if (TypeSpecType == TST_unspecified) { - Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex); - TypeSpecType = TST_double; // _Complex -> _Complex double. - } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { - // Note that this intentionally doesn't include _Complex _Bool. - Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); - } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { - Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec, - getSpecifierName( (TST)TypeSpecType)); - TypeSpecComplex = TSC_unspecified; - } - } - - // Verify __thread. - if (SCS_thread_specified) { - if (StorageClassSpec == SCS_unspecified) { - StorageClassSpec = SCS_extern; // '__thread int' -> 'extern __thread int' - } else if (StorageClassSpec != SCS_extern && - StorageClassSpec != SCS_static) { - Diag(D, getStorageClassSpecLoc(), SrcMgr, diag::err_invalid_thread_spec, - getSpecifierName( (SCS)StorageClassSpec)); - SCS_thread_specified = false; - } - } - - // Okay, now we can infer the real type. - - // TODO: return "auto function" and other bad things based on the real type. - - // 'data definition has no type or storage class'? -} diff --git a/clang/Parse/Makefile b/clang/Parse/Makefile deleted file mode 100644 index 300a99186f4..00000000000 --- a/clang/Parse/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -##===- clang/Parse/Makefile --------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the Parser library for the C-Language front-end. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangParse -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/Parse/MinimalAction.cpp b/clang/Parse/MinimalAction.cpp deleted file mode 100644 index 250fa76ccc4..00000000000 --- a/clang/Parse/MinimalAction.cpp +++ /dev/null @@ -1,136 +0,0 @@ -//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the MinimalAction interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -using namespace clang; - -/// TypeNameInfo - A link exists here for each scope that an identifier is -/// defined. -struct TypeNameInfo { - TypeNameInfo *Prev; - bool isTypeName; - - TypeNameInfo(bool istypename, TypeNameInfo *prev) { - isTypeName = istypename; - Prev = prev; - } -}; - -void MinimalAction:: ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { - TUScope = S; - IdentifierInfo *II; - TypeNameInfo *TI; - - // recognize the ObjC built-in type identifiers. - II = &Idents.get("id"); - TI = new TypeNameInfo(1, II->getFETokenInfo()); - II->setFETokenInfo(TI); - II = &Idents.get("SEL"); - TI = new TypeNameInfo(1, II->getFETokenInfo()); - II->setFETokenInfo(TI); - II = &Idents.get("Class"); - TI = new TypeNameInfo(1, II->getFETokenInfo()); - II->setFETokenInfo(TI); - II = &Idents.get("Protocol"); - TI = new TypeNameInfo(1, II->getFETokenInfo()); - II->setFETokenInfo(TI); -} - -/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to -/// determine whether the name is a type name (objc class name or typedef) or -/// not in this scope. -Action::DeclTy * -MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) const { - if (TypeNameInfo *TI = II.getFETokenInfo()) - if (TI->isTypeName) - return TI; - return 0; -} - -/// ActOnDeclarator - If this is a typedef declarator, we modify the -/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is -/// popped. -Action::DeclTy * -MinimalAction::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) { - IdentifierInfo *II = D.getIdentifier(); - - // If there is no identifier associated with this declarator, bail out. - if (II == 0) return 0; - - TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo(); - bool isTypeName = - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef; - - // this check avoids creating TypeNameInfo objects for the common case. - // It does need to handle the uncommon case of shadowing a typedef name with a - // non-typedef name. e.g. { typedef int a; a xx; { int a; } } - if (weCurrentlyHaveTypeInfo || isTypeName) { - TypeNameInfo *TI = new TypeNameInfo(isTypeName, weCurrentlyHaveTypeInfo); - - II->setFETokenInfo(TI); - - // Remember that this needs to be removed when the scope is popped. - S->AddDecl(II); - } - return 0; -} - -Action::DeclTy * -MinimalAction::ActOnStartClassInterface(SourceLocation AtInterafceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperName, SourceLocation SuperLoc, - IdentifierInfo **ProtocolNames, unsigned NumProtocols, - SourceLocation EndProtoLoc, AttributeList *AttrList) { - TypeNameInfo *TI = - new TypeNameInfo(1, ClassName->getFETokenInfo()); - - ClassName->setFETokenInfo(TI); - return 0; -} - -/// ActOnForwardClassDeclaration - -/// Scope will always be top level file scope. -Action::DeclTy * -MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, - IdentifierInfo **IdentList, unsigned NumElts) { - for (unsigned i = 0; i != NumElts; ++i) { - TypeNameInfo *TI = - new TypeNameInfo(1, IdentList[i]->getFETokenInfo()); - - IdentList[i]->setFETokenInfo(TI); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IdentList[i]); - } - return 0; -} - -/// ActOnPopScope - When a scope is popped, if any typedefs are now out-of-scope, -/// they are removed from the IdentifierInfo::FETokenInfo field. -void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) { - for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); - I != E; ++I) { - IdentifierInfo &II = *static_cast(*I); - TypeNameInfo *TI = II.getFETokenInfo(); - assert(TI && "This decl didn't get pushed??"); - - if (TI) { - TypeNameInfo *Next = TI->Prev; - delete TI; - - II.setFETokenInfo(Next); - } - } -} diff --git a/clang/Parse/ParseDecl.cpp b/clang/Parse/ParseDecl.cpp deleted file mode 100644 index 7d15e984ee6..00000000000 --- a/clang/Parse/ParseDecl.cpp +++ /dev/null @@ -1,1540 +0,0 @@ -//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Declaration portions of the Parser interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "llvm/ADT/SmallSet.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// C99 6.7: Declarations. -//===----------------------------------------------------------------------===// - -/// ParseTypeName -/// type-name: [C99 6.7.6] -/// specifier-qualifier-list abstract-declarator[opt] -Parser::TypeTy *Parser::ParseTypeName() { - // Parse the common declaration-specifiers piece. - DeclSpec DS; - ParseSpecifierQualifierList(DS); - - // Parse the abstract-declarator, if present. - Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); - ParseDeclarator(DeclaratorInfo); - - return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; -} - -/// ParseAttributes - Parse a non-empty attributes list. -/// -/// [GNU] attributes: -/// attribute -/// attributes attribute -/// -/// [GNU] attribute: -/// '__attribute__' '(' '(' attribute-list ')' ')' -/// -/// [GNU] attribute-list: -/// attrib -/// attribute_list ',' attrib -/// -/// [GNU] attrib: -/// empty -/// attrib-name -/// attrib-name '(' identifier ')' -/// attrib-name '(' identifier ',' nonempty-expr-list ')' -/// attrib-name '(' argument-expression-list [C99 6.5.2] ')' -/// -/// [GNU] attrib-name: -/// identifier -/// typespec -/// typequal -/// storageclass -/// -/// FIXME: The GCC grammar/code for this construct implies we need two -/// token lookahead. Comment from gcc: "If they start with an identifier -/// which is followed by a comma or close parenthesis, then the arguments -/// start with that identifier; otherwise they are an expression list." -/// -/// At the moment, I am not doing 2 token lookahead. I am also unaware of -/// any attributes that don't work (based on my limited testing). Most -/// attributes are very simple in practice. Until we find a bug, I don't see -/// a pressing need to implement the 2 token lookahead. - -AttributeList *Parser::ParseAttributes() { - assert(Tok.is(tok::kw___attribute) && "Not an attribute list!"); - - AttributeList *CurrAttr = 0; - - while (Tok.is(tok::kw___attribute)) { - ConsumeToken(); - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, - "attribute")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; - return CurrAttr; - } - if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; - return CurrAttr; - } - // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) - while (Tok.is(tok::identifier) || isDeclarationSpecifier() || - Tok.is(tok::comma)) { - - if (Tok.is(tok::comma)) { - // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) - ConsumeToken(); - continue; - } - // we have an identifier or declaration specifier (const, int, etc.) - IdentifierInfo *AttrName = Tok.getIdentifierInfo(); - SourceLocation AttrNameLoc = ConsumeToken(); - - // check if we have a "paramterized" attribute - if (Tok.is(tok::l_paren)) { - ConsumeParen(); // ignore the left paren loc for now - - if (Tok.is(tok::identifier)) { - IdentifierInfo *ParmName = Tok.getIdentifierInfo(); - SourceLocation ParmLoc = ConsumeToken(); - - if (Tok.is(tok::r_paren)) { - // __attribute__(( mode(byte) )) - ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, - ParmName, ParmLoc, 0, 0, CurrAttr); - } else if (Tok.is(tok::comma)) { - ConsumeToken(); - // __attribute__(( format(printf, 1, 2) )) - llvm::SmallVector ArgExprs; - bool ArgExprsOk = true; - - // now parse the non-empty comma separated list of expressions - while (1) { - ExprResult ArgExpr = ParseAssignmentExpression(); - if (ArgExpr.isInvalid) { - ArgExprsOk = false; - SkipUntil(tok::r_paren); - break; - } else { - ArgExprs.push_back(ArgExpr.Val); - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - if (ArgExprsOk && Tok.is(tok::r_paren)) { - ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, - ParmLoc, &ArgExprs[0], ArgExprs.size(), CurrAttr); - } - } - } else { // not an identifier - // parse a possibly empty comma separated list of expressions - if (Tok.is(tok::r_paren)) { - // __attribute__(( nonnull() )) - ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr); - } else { - // __attribute__(( aligned(16) )) - llvm::SmallVector ArgExprs; - bool ArgExprsOk = true; - - // now parse the list of expressions - while (1) { - ExprResult ArgExpr = ParseAssignmentExpression(); - if (ArgExpr.isInvalid) { - ArgExprsOk = false; - SkipUntil(tok::r_paren); - break; - } else { - ArgExprs.push_back(ArgExpr.Val); - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // Eat the comma, move to the next argument - } - // Match the ')'. - if (ArgExprsOk && Tok.is(tok::r_paren)) { - ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, - SourceLocation(), &ArgExprs[0], ArgExprs.size(), - CurrAttr); - } - } - } - } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr); - } - } - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); - } - return CurrAttr; -} - -/// ParseDeclaration - Parse a full 'declaration', which consists of -/// declaration-specifiers, some number of declarators, and a semicolon. -/// 'Context' should be a Declarator::TheContext value. -/// -/// declaration: [C99 6.7] -/// block-declaration -> -/// simple-declaration -/// others [FIXME] -/// [C++] namespace-definition -/// others... [FIXME] -/// -Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) { - switch (Tok.getKind()) { - case tok::kw_namespace: - return ParseNamespace(Context); - default: - return ParseSimpleDeclaration(Context); - } -} - -/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] -/// declaration-specifiers init-declarator-list[opt] ';' -///[C90/C++]init-declarator-list ';' [TODO] -/// [OMP] threadprivate-directive [TODO] -Parser::DeclTy *Parser::ParseSimpleDeclaration(unsigned Context) { - // Parse the common declaration-specifiers piece. - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - - // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" - // declaration-specifiers init-declarator-list[opt] ';' - if (Tok.is(tok::semi)) { - ConsumeToken(); - return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); - } - - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); - ParseDeclarator(DeclaratorInfo); - - return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); -} - - -/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after -/// parsing 'declaration-specifiers declarator'. This method is split out this -/// way to handle the ambiguity between top-level function-definitions and -/// declarations. -/// -/// init-declarator-list: [C99 6.7] -/// init-declarator -/// init-declarator-list ',' init-declarator -/// init-declarator: [C99 6.7] -/// declarator -/// declarator '=' initializer -/// [GNU] declarator simple-asm-expr[opt] attributes[opt] -/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer -/// -Parser::DeclTy *Parser:: -ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { - - // Declarators may be grouped together ("int X, *Y, Z();"). Provide info so - // that they can be chained properly if the actions want this. - Parser::DeclTy *LastDeclInGroup = 0; - - // At this point, we know that it is not a function definition. Parse the - // rest of the init-declarator-list. - while (1) { - // If a simple-asm-expr is present, parse it. - if (Tok.is(tok::kw_asm)) - ParseSimpleAsm(); - - // If attributes are present, parse them. - if (Tok.is(tok::kw___attribute)) - D.AddAttributes(ParseAttributes()); - - // Inform the current actions module that we just parsed this declarator. - // FIXME: pass asm & attributes. - LastDeclInGroup = Actions.ActOnDeclarator(CurScope, D, LastDeclInGroup); - - // Parse declarator '=' initializer. - ExprResult Init; - if (Tok.is(tok::equal)) { - ConsumeToken(); - Init = ParseInitializer(); - if (Init.isInvalid) { - SkipUntil(tok::semi); - return 0; - } - Actions.AddInitializerToDecl(LastDeclInGroup, Init.Val); - } - - // If we don't have a comma, it is either the end of the list (a ';') or an - // error, bail out. - if (Tok.isNot(tok::comma)) - break; - - // Consume the comma. - ConsumeToken(); - - // Parse the next declarator. - D.clear(); - ParseDeclarator(D); - } - - if (Tok.is(tok::semi)) { - ConsumeToken(); - return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup); - } - // If this is an ObjC2 for-each loop, this is a successful declarator - // parse. The syntax for these looks like: - // 'for' '(' declaration 'in' expr ')' statement - if (D.getContext() == Declarator::ForContext && isTokIdentifier_in()) { - return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup); - } - Diag(Tok, diag::err_parse_error); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return 0; -} - -/// ParseSpecifierQualifierList -/// specifier-qualifier-list: -/// type-specifier specifier-qualifier-list[opt] -/// type-qualifier specifier-qualifier-list[opt] -/// [GNU] attributes specifier-qualifier-list[opt] -/// -void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { - /// specifier-qualifier-list is a subset of declaration-specifiers. Just - /// parse declaration-specifiers and complain about extra stuff. - ParseDeclarationSpecifiers(DS); - - // Validate declspec for type-name. - unsigned Specs = DS.getParsedSpecifiers(); - if (Specs == DeclSpec::PQ_None) - Diag(Tok, diag::err_typename_requires_specqual); - - // Issue diagnostic and remove storage class if present. - if (Specs & DeclSpec::PQ_StorageClassSpecifier) { - if (DS.getStorageClassSpecLoc().isValid()) - Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass); - else - Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass); - DS.ClearStorageClassSpecs(); - } - - // Issue diagnostic and remove function specfier if present. - if (Specs & DeclSpec::PQ_FunctionSpecifier) { - Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); - DS.ClearFunctionSpecs(); - } -} - -/// ParseDeclarationSpecifiers -/// declaration-specifiers: [C99 6.7] -/// storage-class-specifier declaration-specifiers[opt] -/// type-specifier declaration-specifiers[opt] -/// type-qualifier declaration-specifiers[opt] -/// [C99] function-specifier declaration-specifiers[opt] -/// [GNU] attributes declaration-specifiers[opt] -/// -/// storage-class-specifier: [C99 6.7.1] -/// 'typedef' -/// 'extern' -/// 'static' -/// 'auto' -/// 'register' -/// [GNU] '__thread' -/// type-specifier: [C99 6.7.2] -/// 'void' -/// 'char' -/// 'short' -/// 'int' -/// 'long' -/// 'float' -/// 'double' -/// 'signed' -/// 'unsigned' -/// struct-or-union-specifier -/// enum-specifier -/// typedef-name -/// [C++] 'bool' -/// [C99] '_Bool' -/// [C99] '_Complex' -/// [C99] '_Imaginary' // Removed in TC2? -/// [GNU] '_Decimal32' -/// [GNU] '_Decimal64' -/// [GNU] '_Decimal128' -/// [GNU] typeof-specifier -/// [OBJC] class-name objc-protocol-refs[opt] [TODO] -/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] -/// type-qualifier: -/// 'const' -/// 'volatile' -/// [C99] 'restrict' -/// function-specifier: [C99 6.7.4] -/// [C99] 'inline' -/// -void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { - DS.SetRangeStart(Tok.getLocation()); - while (1) { - int isInvalid = false; - const char *PrevSpec = 0; - SourceLocation Loc = Tok.getLocation(); - - switch (Tok.getKind()) { - // typedef-name - case tok::identifier: - // This identifier can only be a typedef name if we haven't already seen - // a type-specifier. Without this check we misparse: - // typedef int X; struct Y { short X; }; as 'short int'. - if (!DS.hasTypeSpecifier()) { - // It has to be available as a typedef too! - if (void *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), - CurScope)) { - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, - TypeRep); - if (isInvalid) - break; - // FIXME: restrict this to "id" and ObjC classnames. - DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); // The identifier - if (Tok.is(tok::less)) { - SourceLocation endProtoLoc; - llvm::SmallVector ProtocolRefs; - ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc); - llvm::SmallVector *ProtocolDecl = - new llvm::SmallVector; - DS.setProtocolQualifiers(ProtocolDecl); - Actions.FindProtocolDeclaration(Loc, - &ProtocolRefs[0], ProtocolRefs.size(), - *ProtocolDecl); - } - continue; - } - } - // FALL THROUGH. - default: - // If this is not a declaration specifier token, we're done reading decl - // specifiers. First verify that DeclSpec's are consistent. - DS.Finish(Diags, PP.getSourceManager(), getLang()); - return; - - // GNU attributes support. - case tok::kw___attribute: - DS.AddAttributes(ParseAttributes()); - continue; - - // storage-class-specifier - case tok::kw_typedef: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec); - break; - case tok::kw_extern: - if (DS.isThreadSpecified()) - Diag(Tok, diag::ext_thread_before, "extern"); - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec); - break; - case tok::kw___private_extern__: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, PrevSpec); - break; - case tok::kw_static: - if (DS.isThreadSpecified()) - Diag(Tok, diag::ext_thread_before, "static"); - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec); - break; - case tok::kw_auto: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec); - break; - case tok::kw_register: - isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec); - break; - case tok::kw___thread: - isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2; - break; - - // type-specifiers - case tok::kw_short: - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); - break; - case tok::kw_long: - if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); - else - isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec); - break; - case tok::kw_signed: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); - break; - case tok::kw_unsigned: - isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); - break; - case tok::kw__Complex: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec); - break; - case tok::kw__Imaginary: - isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec); - break; - case tok::kw_void: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); - break; - case tok::kw_char: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); - break; - case tok::kw_int: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); - break; - case tok::kw_float: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); - break; - case tok::kw_double: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); - break; - case tok::kw_bool: // [C++ 2.11p1] - case tok::kw__Bool: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec); - break; - case tok::kw__Decimal32: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec); - break; - case tok::kw__Decimal64: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec); - break; - case tok::kw__Decimal128: - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec); - break; - - case tok::kw_struct: - case tok::kw_union: - ParseStructUnionSpecifier(DS); - continue; - case tok::kw_enum: - ParseEnumSpecifier(DS); - continue; - - // GNU typeof support. - case tok::kw_typeof: - ParseTypeofSpecifier(DS); - continue; - - // type-qualifier - case tok::kw_const: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, - getLang())*2; - break; - case tok::kw_volatile: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, - getLang())*2; - break; - case tok::kw_restrict: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, - getLang())*2; - break; - - // function-specifier - case tok::kw_inline: - isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec); - break; - } - // If the specifier combination wasn't legal, issue a diagnostic. - if (isInvalid) { - assert(PrevSpec && "Method did not return previous specifier!"); - if (isInvalid == 1) // Error. - Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec); - else // extwarn. - Diag(Tok, diag::ext_duplicate_declspec, PrevSpec); - } - DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); - } -} - -/// ParseTag - Parse "struct-or-union-or-class-or-enum identifier[opt]", where -/// the first token has already been read and has been turned into an instance -/// of DeclSpec::TST (TagType). This returns true if there is an error parsing, -/// otherwise it returns false and fills in Decl. -bool Parser::ParseTag(DeclTy *&Decl, unsigned TagType, SourceLocation StartLoc){ - AttributeList *Attr = 0; - // If attributes exist after tag, parse them. - if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); - - // Must have either 'struct name' or 'struct {...}'. - if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) { - Diag(Tok, diag::err_expected_ident_lbrace); - - // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); - return true; - } - - // If an identifier is present, consume and remember it. - IdentifierInfo *Name = 0; - SourceLocation NameLoc; - if (Tok.is(tok::identifier)) { - Name = Tok.getIdentifierInfo(); - NameLoc = ConsumeToken(); - } - - // There are three options here. If we have 'struct foo;', then this is a - // forward declaration. If we have 'struct foo {...' then this is a - // definition. Otherwise we have something like 'struct foo xyz', a reference. - // - // This is needed to handle stuff like this right (C99 6.7.2.3p11): - // struct foo {..}; void bar() { struct foo; } <- new foo in bar. - // struct foo {..}; void bar() { struct foo x; } <- use of old foo. - // - Action::TagKind TK; - if (Tok.is(tok::l_brace)) - TK = Action::TK_Definition; - else if (Tok.is(tok::semi)) - TK = Action::TK_Declaration; - else - TK = Action::TK_Reference; - Decl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, Name, NameLoc, Attr); - return false; -} - - -/// ParseStructUnionSpecifier -/// struct-or-union-specifier: [C99 6.7.2.1] -/// struct-or-union identifier[opt] '{' struct-contents '}' -/// struct-or-union identifier -/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents -/// '}' attributes[opt] -/// [GNU] struct-or-union attributes[opt] identifier -/// struct-or-union: -/// 'struct' -/// 'union' -/// -void Parser::ParseStructUnionSpecifier(DeclSpec &DS) { - assert((Tok.is(tok::kw_struct) || Tok.is(tok::kw_union)) && - "Not a struct/union specifier"); - DeclSpec::TST TagType = - Tok.is(tok::kw_union) ? DeclSpec::TST_union : DeclSpec::TST_struct; - SourceLocation StartLoc = ConsumeToken(); - - // Parse the tag portion of this. - DeclTy *TagDecl; - if (ParseTag(TagDecl, TagType, StartLoc)) - return; - - // If there is a body, parse it and inform the actions module. - if (Tok.is(tok::l_brace)) - ParseStructUnionBody(StartLoc, TagType, TagDecl); - - const char *PrevSpec = 0; - if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, TagDecl)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); -} - -/// ParseStructDeclaration - Parse a struct declaration without the terminating -/// semicolon. -/// -/// struct-declaration: -/// specifier-qualifier-list struct-declarator-list -/// [GNU] __extension__ struct-declaration -/// [GNU] specifier-qualifier-list -/// struct-declarator-list: -/// struct-declarator -/// struct-declarator-list ',' struct-declarator -/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator -/// struct-declarator: -/// declarator -/// [GNU] declarator attributes[opt] -/// declarator[opt] ':' constant-expression -/// [GNU] declarator[opt] ':' constant-expression attributes[opt] -/// -void Parser::ParseStructDeclaration(DeclTy *TagDecl, - llvm::SmallVectorImpl &FieldDecls) { - // FIXME: When __extension__ is specified, disable extension diagnostics. - if (Tok.is(tok::kw___extension__)) - ConsumeToken(); - - // Parse the common specifier-qualifiers-list piece. - DeclSpec DS; - SourceLocation SpecQualLoc = Tok.getLocation(); - ParseSpecifierQualifierList(DS); - // TODO: Does specifier-qualifier list correctly check that *something* is - // specified? - - // If there are no declarators, issue a warning. - if (Tok.is(tok::semi)) { - Diag(SpecQualLoc, diag::w_no_declarators); - return; - } - - // Read struct-declarators until we find the semicolon. - Declarator DeclaratorInfo(DS, Declarator::MemberContext); - - while (1) { - /// struct-declarator: declarator - /// struct-declarator: declarator[opt] ':' constant-expression - if (Tok.isNot(tok::colon)) - ParseDeclarator(DeclaratorInfo); - - ExprTy *BitfieldSize = 0; - if (Tok.is(tok::colon)) { - ConsumeToken(); - ExprResult Res = ParseConstantExpression(); - if (Res.isInvalid) { - SkipUntil(tok::semi, true, true); - } else { - BitfieldSize = Res.Val; - } - } - - // If attributes exist after the declarator, parse them. - if (Tok.is(tok::kw___attribute)) - DeclaratorInfo.AddAttributes(ParseAttributes()); - - // Install the declarator into the current TagDecl. - DeclTy *Field = Actions.ActOnField(CurScope, TagDecl, SpecQualLoc, - DeclaratorInfo, BitfieldSize); - FieldDecls.push_back(Field); - - // If we don't have a comma, it is either the end of the list (a ';') - // or an error, bail out. - if (Tok.isNot(tok::comma)) - return; - - // Consume the comma. - ConsumeToken(); - - // Parse the next declarator. - DeclaratorInfo.clear(); - - // Attributes are only allowed on the second declarator. - if (Tok.is(tok::kw___attribute)) - DeclaratorInfo.AddAttributes(ParseAttributes()); - } -} - -/// ParseStructUnionBody -/// struct-contents: -/// struct-declaration-list -/// [EXT] empty -/// [GNU] "struct-declaration-list" without terminatoring ';' -/// struct-declaration-list: -/// struct-declaration -/// struct-declaration-list struct-declaration -/// [OBC] '@' 'defs' '(' class-name ')' [TODO] -/// -void Parser::ParseStructUnionBody(SourceLocation RecordLoc, - unsigned TagType, DeclTy *TagDecl) { - SourceLocation LBraceLoc = ConsumeBrace(); - - // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in - // C++. - if (Tok.is(tok::r_brace)) - Diag(Tok, diag::ext_empty_struct_union_enum, - DeclSpec::getSpecifierName((DeclSpec::TST)TagType)); - - llvm::SmallVector FieldDecls; - - // While we still have something to read, read the declarations in the struct. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - // Each iteration of this loop reads one struct-declaration. - - // Check for extraneous top-level semicolon. - if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi); - ConsumeToken(); - continue; - } - ParseStructDeclaration(TagDecl, FieldDecls); - - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else if (Tok.is(tok::r_brace)) { - Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list); - break; - } else { - Diag(Tok, diag::err_expected_semi_decl_list); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - } - } - - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - - Actions.ActOnFields(CurScope, - RecordLoc,TagDecl,&FieldDecls[0],FieldDecls.size(), - LBraceLoc, RBraceLoc); - - AttributeList *AttrList = 0; - // If attributes exist after struct contents, parse them. - if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); // FIXME: where should I put them? -} - - -/// ParseEnumSpecifier -/// enum-specifier: [C99 6.7.2.2] -/// 'enum' identifier[opt] '{' enumerator-list '}' -/// [C99] 'enum' identifier[opt] '{' enumerator-list ',' '}' -/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] -/// '}' attributes[opt] -/// 'enum' identifier -/// [GNU] 'enum' attributes[opt] identifier -void Parser::ParseEnumSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw_enum) && "Not an enum specifier"); - SourceLocation StartLoc = ConsumeToken(); - - // Parse the tag portion of this. - DeclTy *TagDecl; - if (ParseTag(TagDecl, DeclSpec::TST_enum, StartLoc)) - return; - - if (Tok.is(tok::l_brace)) - ParseEnumBody(StartLoc, TagDecl); - - // TODO: semantic analysis on the declspec for enums. - const char *PrevSpec = 0; - if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); -} - -/// ParseEnumBody - Parse a {} enclosed enumerator-list. -/// enumerator-list: -/// enumerator -/// enumerator-list ',' enumerator -/// enumerator: -/// enumeration-constant -/// enumeration-constant '=' constant-expression -/// enumeration-constant: -/// identifier -/// -void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { - SourceLocation LBraceLoc = ConsumeBrace(); - - // C does not allow an empty enumerator-list, C++ does [dcl.enum]. - if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) - Diag(Tok, diag::ext_empty_struct_union_enum, "enum"); - - llvm::SmallVector EnumConstantDecls; - - DeclTy *LastEnumConstDecl = 0; - - // Parse the enumerator-list. - while (Tok.is(tok::identifier)) { - IdentifierInfo *Ident = Tok.getIdentifierInfo(); - SourceLocation IdentLoc = ConsumeToken(); - - SourceLocation EqualLoc; - ExprTy *AssignedVal = 0; - if (Tok.is(tok::equal)) { - EqualLoc = ConsumeToken(); - ExprResult Res = ParseConstantExpression(); - if (Res.isInvalid) - SkipUntil(tok::comma, tok::r_brace, true, true); - else - AssignedVal = Res.Val; - } - - // Install the enumerator constant into EnumDecl. - DeclTy *EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl, - LastEnumConstDecl, - IdentLoc, Ident, - EqualLoc, AssignedVal); - EnumConstantDecls.push_back(EnumConstDecl); - LastEnumConstDecl = EnumConstDecl; - - if (Tok.isNot(tok::comma)) - break; - SourceLocation CommaLoc = ConsumeToken(); - - if (Tok.isNot(tok::identifier) && !getLang().C99) - Diag(CommaLoc, diag::ext_c99_enumerator_list_comma); - } - - // Eat the }. - MatchRHSPunctuation(tok::r_brace, LBraceLoc); - - Actions.ActOnEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0], - EnumConstantDecls.size()); - - DeclTy *AttrList = 0; - // If attributes exist after the identifier list, parse them. - if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); // FIXME: where do they do? -} - -/// isTypeSpecifierQualifier - Return true if the current token could be the -/// start of a type-qualifier-list. -bool Parser::isTypeQualifier() const { - switch (Tok.getKind()) { - default: return false; - // type-qualifier - case tok::kw_const: - case tok::kw_volatile: - case tok::kw_restrict: - return true; - } -} - -/// isTypeSpecifierQualifier - Return true if the current token could be the -/// start of a specifier-qualifier-list. -bool Parser::isTypeSpecifierQualifier() const { - switch (Tok.getKind()) { - default: return false; - // GNU attributes support. - case tok::kw___attribute: - // GNU typeof support. - case tok::kw_typeof: - - // type-specifiers - case tok::kw_short: - case tok::kw_long: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw__Complex: - case tok::kw__Imaginary: - case tok::kw_void: - case tok::kw_char: - case tok::kw_int: - case tok::kw_float: - case tok::kw_double: - case tok::kw_bool: - case tok::kw__Bool: - case tok::kw__Decimal32: - case tok::kw__Decimal64: - case tok::kw__Decimal128: - - // struct-or-union-specifier - case tok::kw_struct: - case tok::kw_union: - // enum-specifier - case tok::kw_enum: - - // type-qualifier - case tok::kw_const: - case tok::kw_volatile: - case tok::kw_restrict: - return true; - - // typedef-name - case tok::identifier: - return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0; - } -} - -/// isDeclarationSpecifier() - Return true if the current token is part of a -/// declaration specifier. -bool Parser::isDeclarationSpecifier() const { - switch (Tok.getKind()) { - default: return false; - // storage-class-specifier - case tok::kw_typedef: - case tok::kw_extern: - case tok::kw___private_extern__: - case tok::kw_static: - case tok::kw_auto: - case tok::kw_register: - case tok::kw___thread: - - // type-specifiers - case tok::kw_short: - case tok::kw_long: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw__Complex: - case tok::kw__Imaginary: - case tok::kw_void: - case tok::kw_char: - case tok::kw_int: - case tok::kw_float: - case tok::kw_double: - case tok::kw_bool: - case tok::kw__Bool: - case tok::kw__Decimal32: - case tok::kw__Decimal64: - case tok::kw__Decimal128: - - // struct-or-union-specifier - case tok::kw_struct: - case tok::kw_union: - // enum-specifier - case tok::kw_enum: - - // type-qualifier - case tok::kw_const: - case tok::kw_volatile: - case tok::kw_restrict: - - // function-specifier - case tok::kw_inline: - - // GNU typeof support. - case tok::kw_typeof: - - // GNU attributes. - case tok::kw___attribute: - return true; - - // typedef-name - case tok::identifier: - return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0; - } -} - - -/// ParseTypeQualifierListOpt -/// type-qualifier-list: [C99 6.7.5] -/// type-qualifier -/// [GNU] attributes -/// type-qualifier-list type-qualifier -/// [GNU] type-qualifier-list attributes -/// -void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) { - while (1) { - int isInvalid = false; - const char *PrevSpec = 0; - SourceLocation Loc = Tok.getLocation(); - - switch (Tok.getKind()) { - default: - // If this is not a type-qualifier token, we're done reading type - // qualifiers. First verify that DeclSpec's are consistent. - DS.Finish(Diags, PP.getSourceManager(), getLang()); - return; - case tok::kw_const: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, - getLang())*2; - break; - case tok::kw_volatile: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, - getLang())*2; - break; - case tok::kw_restrict: - isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, - getLang())*2; - break; - case tok::kw___attribute: - DS.AddAttributes(ParseAttributes()); - continue; // do *not* consume the next token! - } - - // If the specifier combination wasn't legal, issue a diagnostic. - if (isInvalid) { - assert(PrevSpec && "Method did not return previous specifier!"); - if (isInvalid == 1) // Error. - Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec); - else // extwarn. - Diag(Tok, diag::ext_duplicate_declspec, PrevSpec); - } - ConsumeToken(); - } -} - - -/// ParseDeclarator - Parse and verify a newly-initialized declarator. -/// -void Parser::ParseDeclarator(Declarator &D) { - /// This implements the 'declarator' production in the C grammar, then checks - /// for well-formedness and issues diagnostics. - ParseDeclaratorInternal(D); - - // TODO: validate D. - -} - -/// ParseDeclaratorInternal -/// declarator: [C99 6.7.5] -/// pointer[opt] direct-declarator -/// [C++] '&' declarator [C++ 8p4, dcl.decl] -/// [GNU] '&' restrict[opt] attributes[opt] declarator -/// -/// pointer: [C99 6.7.5] -/// '*' type-qualifier-list[opt] -/// '*' type-qualifier-list[opt] pointer -/// -void Parser::ParseDeclaratorInternal(Declarator &D) { - tok::TokenKind Kind = Tok.getKind(); - - // Not a pointer or C++ reference. - if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus)) - return ParseDirectDeclarator(D); - - // Otherwise, '*' -> pointer or '&' -> reference. - SourceLocation Loc = ConsumeToken(); // Eat the * or &. - - if (Kind == tok::star) { - // Is a pointer. - DeclSpec DS; - - ParseTypeQualifierListOpt(DS); - - // Recursively parse the declarator. - ParseDeclaratorInternal(D); - - // Remember that we parsed a pointer type, and remember the type-quals. - D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, - DS.TakeAttributes())); - } else { - // Is a reference - DeclSpec DS; - - // C++ 8.3.2p1: cv-qualified references are ill-formed except when the - // cv-qualifiers are introduced through the use of a typedef or of a - // template type argument, in which case the cv-qualifiers are ignored. - // - // [GNU] Retricted references are allowed. - // [GNU] Attributes on references are allowed. - ParseTypeQualifierListOpt(DS); - - if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { - if (DS.getTypeQualifiers() & DeclSpec::TQ_const) - Diag(DS.getConstSpecLoc(), - diag::err_invalid_reference_qualifier_application, - "const"); - if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) - Diag(DS.getVolatileSpecLoc(), - diag::err_invalid_reference_qualifier_application, - "volatile"); - } - - // Recursively parse the declarator. - ParseDeclaratorInternal(D); - - // Remember that we parsed a reference type. It doesn't have type-quals. - D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, - DS.TakeAttributes())); - } -} - -/// ParseDirectDeclarator -/// direct-declarator: [C99 6.7.5] -/// identifier -/// '(' declarator ')' -/// [GNU] '(' attributes declarator ')' -/// [C90] direct-declarator '[' constant-expression[opt] ']' -/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' -/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' -/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' -/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' -/// direct-declarator '(' parameter-type-list ')' -/// direct-declarator '(' identifier-list[opt] ')' -/// [GNU] direct-declarator '(' parameter-forward-declarations -/// parameter-type-list[opt] ')' -/// -void Parser::ParseDirectDeclarator(Declarator &D) { - // Parse the first direct-declarator seen. - if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { - assert(Tok.getIdentifierInfo() && "Not an identifier?"); - D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeToken(); - } else if (Tok.is(tok::l_paren)) { - // direct-declarator: '(' declarator ')' - // direct-declarator: '(' attributes declarator ')' - // Example: 'char (*X)' or 'int (*XX)(void)' - ParseParenDeclarator(D); - } else if (D.mayOmitIdentifier()) { - // This could be something simple like "int" (in which case the declarator - // portion is empty), if an abstract-declarator is allowed. - D.SetIdentifier(0, Tok.getLocation()); - } else { - // Expected identifier or '('. - Diag(Tok, diag::err_expected_ident_lparen); - D.SetIdentifier(0, Tok.getLocation()); - } - - assert(D.isPastIdentifier() && - "Haven't past the location of the identifier yet?"); - - while (1) { - if (Tok.is(tok::l_paren)) { - ParseParenDeclarator(D); - } else if (Tok.is(tok::l_square)) { - ParseBracketDeclarator(D); - } else { - break; - } - } -} - -/// ParseParenDeclarator - We parsed the declarator D up to a paren. This may -/// either be before the identifier (in which case these are just grouping -/// parens for precedence) or it may be after the identifier, in which case -/// these are function arguments. -/// -/// This method also handles this portion of the grammar: -/// parameter-type-list: [C99 6.7.5] -/// parameter-list -/// parameter-list ',' '...' -/// -/// parameter-list: [C99 6.7.5] -/// parameter-declaration -/// parameter-list ',' parameter-declaration -/// -/// parameter-declaration: [C99 6.7.5] -/// declaration-specifiers declarator -/// [GNU] declaration-specifiers declarator attributes -/// declaration-specifiers abstract-declarator[opt] -/// [GNU] declaration-specifiers abstract-declarator[opt] attributes -/// -/// identifier-list: [C99 6.7.5] -/// identifier -/// identifier-list ',' identifier -/// -void Parser::ParseParenDeclarator(Declarator &D) { - SourceLocation StartLoc = ConsumeParen(); - - // If we haven't past the identifier yet (or where the identifier would be - // stored, if this is an abstract declarator), then this is probably just - // grouping parens. - if (!D.isPastIdentifier()) { - // Okay, this is probably a grouping paren. However, if this could be an - // abstract-declarator, then this could also be the start of function - // arguments (consider 'void()'). - bool isGrouping; - - if (!D.mayOmitIdentifier()) { - // If this can't be an abstract-declarator, this *must* be a grouping - // paren, because we haven't seen the identifier yet. - isGrouping = true; - } else if (Tok.is(tok::r_paren) || // 'int()' is a function. - isDeclarationSpecifier()) { // 'int(int)' is a function. - // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is - // considered to be a type, not a K&R identifier-list. - isGrouping = false; - } else { - // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'. - isGrouping = true; - } - - // If this is a grouping paren, handle: - // direct-declarator: '(' declarator ')' - // direct-declarator: '(' attributes declarator ')' - if (isGrouping) { - if (Tok.is(tok::kw___attribute)) - D.AddAttributes(ParseAttributes()); - - ParseDeclaratorInternal(D); - // Match the ')'. - MatchRHSPunctuation(tok::r_paren, StartLoc); - return; - } - - // Okay, if this wasn't a grouping paren, it must be the start of a function - // argument list. Recognize that this declarator will never have an - // identifier (and remember where it would have been), then fall through to - // the handling of argument lists. - D.SetIdentifier(0, Tok.getLocation()); - } - - // Okay, this is the parameter list of a function definition, or it is an - // identifier list of a K&R-style function. - bool IsVariadic; - bool HasPrototype; - bool ErrorEmitted = false; - - // Build up an array of information about the parsed arguments. - llvm::SmallVector ParamInfo; - llvm::SmallSet ParamsSoFar; - - if (Tok.is(tok::r_paren)) { - // int() -> no prototype, no '...'. - IsVariadic = false; - HasPrototype = false; - } else if (Tok.is(tok::identifier) && - // K&R identifier lists can't have typedefs as identifiers, per - // C99 6.7.5.3p11. - !Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { - // Identifier list. Note that '(' identifier-list ')' is only allowed for - // normal declarators, not for abstract-declarators. - assert(D.isPastIdentifier() && "Identifier (if present) must be passed!"); - - // If there was no identifier specified, either we are in an - // abstract-declarator, or we are in a parameter declarator which was found - // to be abstract. In abstract-declarators, identifier lists are not valid, - // diagnose this. - if (!D.getIdentifier()) - Diag(Tok, diag::ext_ident_list_in_param); - - // Remember this identifier in ParamInfo. - ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(), - Tok.getLocation(), 0)); - - ConsumeToken(); - while (Tok.is(tok::comma)) { - // Eat the comma. - ConsumeToken(); - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - ErrorEmitted = true; - break; - } - - IdentifierInfo *ParmII = Tok.getIdentifierInfo(); - - // Verify that the argument identifier has not already been mentioned. - if (!ParamsSoFar.insert(ParmII)) { - Diag(Tok.getLocation(), diag::err_param_redefinition,ParmII->getName()); - ParmII = 0; - } - - // Remember this identifier in ParamInfo. - if (ParmII) - ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - Tok.getLocation(), 0)); - - // Eat the identifier. - ConsumeToken(); - } - - // K&R 'prototype'. - IsVariadic = false; - HasPrototype = false; - } else { - // Finally, a normal, non-empty parameter type list. - - // Enter function-declaration scope, limiting any declarators for struct - // tags to the function prototype scope. - // FIXME: is this needed? - EnterScope(Scope::DeclScope); - - IsVariadic = false; - while (1) { - if (Tok.is(tok::ellipsis)) { - IsVariadic = true; - - // Check to see if this is "void(...)" which is not allowed. - if (ParamInfo.empty()) { - // Otherwise, parse parameter type list. If it starts with an - // ellipsis, diagnose the malformed function. - Diag(Tok, diag::err_ellipsis_first_arg); - IsVariadic = false; // Treat this like 'void()'. - } - - // Consume the ellipsis. - ConsumeToken(); - break; - } - - SourceLocation DSStart = Tok.getLocation(); - - // Parse the declaration-specifiers. - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - - // Parse the declarator. This is "PrototypeContext", because we must - // accept either 'declarator' or 'abstract-declarator' here. - Declarator ParmDecl(DS, Declarator::PrototypeContext); - ParseDeclarator(ParmDecl); - - // Parse GNU attributes, if present. - if (Tok.is(tok::kw___attribute)) - ParmDecl.AddAttributes(ParseAttributes()); - - // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. - // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted. - if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && - DS.getStorageClassSpec() != DeclSpec::SCS_register) { - Diag(DS.getStorageClassSpecLoc(), - diag::err_invalid_storage_class_in_func_decl); - DS.ClearStorageClassSpecs(); - } - if (DS.isThreadSpecified()) { - Diag(DS.getThreadSpecLoc(), - diag::err_invalid_storage_class_in_func_decl); - DS.ClearStorageClassSpecs(); - } - - // Inform the actions module about the parameter declarator, so it gets - // added to the current scope. - Action::TypeResult ParamTy = - Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); - - // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDecl.getIdentifier(); - - // Verify that the argument identifier has not already been mentioned. - if (ParmII && !ParamsSoFar.insert(ParmII)) { - Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition, - ParmII->getName()); - ParmII = 0; - } - - // If no parameter was specified, verify that *something* was specified, - // otherwise we have a missing type and identifier. - if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && - ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) { - Diag(DSStart, diag::err_missing_param); - } else if (!DS.hasTypeSpecifier() && - (getLang().C99 || getLang().CPlusPlus)) { - // Otherwise, if something was specified but a type specifier wasn't, - // (e.g. "x" or "restrict x" or "restrict"), this is a use of implicit - // int. This is valid in C90, but not in C99 or C++. - if (ParmII) - Diag(ParmDecl.getIdentifierLoc(), - diag::ext_param_requires_type_specifier, ParmII->getName()); - else - Diag(DSStart, diag::ext_anon_param_requires_type_specifier); - } - - ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), - ParmDecl.getDeclSpec().TakeAttributes())); - - // If the next token is a comma, consume it and keep reading arguments. - if (Tok.isNot(tok::comma)) break; - - // Consume the comma. - ConsumeToken(); - } - - HasPrototype = true; - - // Leave prototype scope. - ExitScope(); - } - - // Remember that we parsed a function type, and remember the attributes. - if (!ErrorEmitted) - D.AddTypeInfo(DeclaratorChunk::getFunction(HasPrototype, IsVariadic, - &ParamInfo[0], ParamInfo.size(), - StartLoc)); - - // If we have the closing ')', eat it and we're done. - if (Tok.is(tok::r_paren)) { - ConsumeParen(); - } else { - // If an error happened earlier parsing something else in the proto, don't - // issue another error. - if (!ErrorEmitted) - Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren); - } -} - - -/// [C90] direct-declarator '[' constant-expression[opt] ']' -/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' -/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' -/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' -/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' -void Parser::ParseBracketDeclarator(Declarator &D) { - SourceLocation StartLoc = ConsumeBracket(); - - // If valid, this location is the position where we read the 'static' keyword. - SourceLocation StaticLoc; - if (Tok.is(tok::kw_static)) - StaticLoc = ConsumeToken(); - - // If there is a type-qualifier-list, read it now. - DeclSpec DS; - ParseTypeQualifierListOpt(DS); - - // If we haven't already read 'static', check to see if there is one after the - // type-qualifier-list. - if (!StaticLoc.isValid() && Tok.is(tok::kw_static)) - StaticLoc = ConsumeToken(); - - // Handle "direct-declarator [ type-qual-list[opt] * ]". - bool isStar = false; - ExprResult NumElements(false); - if (Tok.is(tok::star)) { - // Remember the '*' token, in case we have to un-get it. - Token StarTok = Tok; - ConsumeToken(); - - // Check that the ']' token is present to avoid incorrectly parsing - // expressions starting with '*' as [*]. - if (Tok.is(tok::r_square)) { - if (StaticLoc.isValid()) - Diag(StaticLoc, diag::err_unspecified_vla_size_with_static); - StaticLoc = SourceLocation(); // Drop the static. - isStar = true; - } else { - // Otherwise, the * must have been some expression (such as '*ptr') that - // started an assignment-expr. We already consumed the token, but now we - // need to reparse it. This handles cases like 'X[*p + 4]' - NumElements = ParseAssignmentExpressionWithLeadingStar(StarTok); - } - } else if (Tok.isNot(tok::r_square)) { - // Parse the assignment-expression now. - NumElements = ParseAssignmentExpression(); - } - - // If there was an error parsing the assignment-expression, recover. - if (NumElements.isInvalid) { - // If the expression was invalid, skip it. - SkipUntil(tok::r_square); - return; - } - - MatchRHSPunctuation(tok::r_square, StartLoc); - - // If C99 isn't enabled, emit an ext-warn if the arg list wasn't empty and if - // it was not a constant expression. - if (!getLang().C99) { - // TODO: check C90 array constant exprness. - if (isStar || StaticLoc.isValid() || - 0/*TODO: NumElts is not a C90 constantexpr */) - Diag(StartLoc, diag::ext_c99_array_usage); - } - - // Remember that we parsed a pointer type, and remember the type-quals. - D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), - StaticLoc.isValid(), isStar, - NumElements.Val, StartLoc)); -} - -/// [GNU] typeof-specifier: -/// typeof ( expressions ) -/// typeof ( type-name ) -/// -void Parser::ParseTypeofSpecifier(DeclSpec &DS) { - assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier"); - const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); - SourceLocation StartLoc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName()); - return; - } - SourceLocation LParenLoc = ConsumeParen(), RParenLoc; - - if (isTypeSpecifierQualifier()) { - TypeTy *Ty = ParseTypeName(); - - assert(Ty && "Parser::ParseTypeofSpecifier(): missing type"); - - if (Tok.isNot(tok::r_paren)) { - MatchRHSPunctuation(tok::r_paren, LParenLoc); - return; - } - RParenLoc = ConsumeParen(); - const char *PrevSpec = 0; - // Check for duplicate type specifiers (e.g. "int typeof(int)"). - if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, Ty)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); - } else { // we have an expression. - ExprResult Result = ParseExpression(); - - if (Result.isInvalid || Tok.isNot(tok::r_paren)) { - MatchRHSPunctuation(tok::r_paren, LParenLoc); - return; - } - RParenLoc = ConsumeParen(); - const char *PrevSpec = 0; - // Check for duplicate type specifiers (e.g. "int typeof(int)"). - if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, - Result.Val)) - Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); - } -} - diff --git a/clang/Parse/ParseDeclCXX.cpp b/clang/Parse/ParseDeclCXX.cpp deleted file mode 100644 index 46dcb574819..00000000000 --- a/clang/Parse/ParseDeclCXX.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the C++ Declaration portions of the Parser interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/Scope.h" -#include "clang/Basic/Diagnostic.h" -using namespace clang; - -/// ParseNamespace - We know that the current token is a namespace keyword. This -/// may either be a top level namespace or a block-level namespace alias. -/// -/// namespace-definition: [C++ 7.3: basic.namespace] -/// named-namespace-definition -/// unnamed-namespace-definition -/// -/// unnamed-namespace-definition: -/// 'namespace' attributes[opt] '{' namespace-body '}' -/// -/// named-namespace-definition: -/// original-namespace-definition -/// extension-namespace-definition -/// -/// original-namespace-definition: -/// 'namespace' identifier attributes[opt] '{' namespace-body '}' -/// -/// extension-namespace-definition: -/// 'namespace' original-namespace-name '{' namespace-body '}' -/// -/// namespace-alias-definition: [C++ 7.3.2: namespace.alias] -/// 'namespace' identifier '=' qualified-namespace-specifier ';' -/// -Parser::DeclTy *Parser::ParseNamespace(unsigned Context) { - assert(Tok.is(tok::kw_namespace) && "Not a namespace!"); - SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'. - - SourceLocation IdentLoc; - IdentifierInfo *Ident = 0; - - if (Tok.is(tok::identifier)) { - Ident = Tok.getIdentifierInfo(); - IdentLoc = ConsumeToken(); // eat the identifier. - } - - // Read label attributes, if present. - DeclTy *AttrList = 0; - if (Tok.is(tok::kw___attribute)) - // FIXME: save these somewhere. - AttrList = ParseAttributes(); - - if (Tok.is(tok::equal)) { - // FIXME: Verify no attributes were present. - // FIXME: parse this. - } else if (Tok.is(tok::l_brace)) { - SourceLocation LBrace = ConsumeBrace(); - // FIXME: push a scope, push a namespace decl. - - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - // FIXME capture the decls. - ParseExternalDeclaration(); - } - - SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); - - // FIXME: act on this. - } else { - unsigned D = Ident ? diag::err_expected_lbrace : - diag::err_expected_ident_lbrace; - Diag(Tok.getLocation(), D); - } - - return 0; -} - -/// ParseLinkage - We know that the current token is a string_literal -/// and just before that, that extern was seen. -/// -/// linkage-specification: [C++ 7.5p2: dcl.link] -/// 'extern' string-literal '{' declaration-seq[opt] '}' -/// 'extern' string-literal declaration -/// -Parser::DeclTy *Parser::ParseLinkage(unsigned Context) { - assert(Tok.is(tok::string_literal) && "Not a stringliteral!"); - llvm::SmallVector LangBuffer; - // LangBuffer is guaranteed to be big enough. - LangBuffer.resize(Tok.getLength()); - const char *LangBufPtr = &LangBuffer[0]; - unsigned StrSize = PP.getSpelling(Tok, LangBufPtr); - - SourceLocation Loc = ConsumeStringToken(); - DeclTy *D = 0; - SourceLocation LBrace, RBrace; - - if (Tok.isNot(tok::l_brace)) { - D = ParseDeclaration(Context); - } else { - LBrace = ConsumeBrace(); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - // FIXME capture the decls. - D = ParseExternalDeclaration(); - } - - RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); - } - - if (!D) - return 0; - - return Actions.ActOnLinkageSpec(Loc, LBrace, RBrace, LangBufPtr, StrSize, D); -} diff --git a/clang/Parse/ParseExpr.cpp b/clang/Parse/ParseExpr.cpp deleted file mode 100644 index 46714b73ea7..00000000000 --- a/clang/Parse/ParseExpr.cpp +++ /dev/null @@ -1,1081 +0,0 @@ -//===--- ParseExpr.cpp - Expression Parsing -------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Expression parsing implementation. Expressions in -// C99 basically consist of a bunch of binary operators with unary operators and -// other random stuff at the leaves. -// -// In the C99 grammar, these unary operators bind tightest and are represented -// as the 'cast-expression' production. Everything else is either a binary -// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are -// handled by ParseCastExpression, the higher level pieces are handled by -// ParseBinaryExpression. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/SmallString.h" -using namespace clang; - -/// PrecedenceLevels - These are precedences for the binary/ternary operators in -/// the C99 grammar. These have been named to relate with the C99 grammar -/// productions. Low precedences numbers bind more weakly than high numbers. -namespace prec { - enum Level { - Unknown = 0, // Not binary operator. - Comma = 1, // , - Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= - Conditional = 3, // ? - LogicalOr = 4, // || - LogicalAnd = 5, // && - InclusiveOr = 6, // | - ExclusiveOr = 7, // ^ - And = 8, // & - Equality = 9, // ==, != - Relational = 10, // >=, <=, >, < - Shift = 11, // <<, >> - Additive = 12, // -, + - Multiplicative = 13 // *, /, % - }; -} - - -/// getBinOpPrecedence - Return the precedence of the specified binary operator -/// token. This returns: -/// -static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { - switch (Kind) { - default: return prec::Unknown; - case tok::comma: return prec::Comma; - case tok::equal: - case tok::starequal: - case tok::slashequal: - case tok::percentequal: - case tok::plusequal: - case tok::minusequal: - case tok::lesslessequal: - case tok::greatergreaterequal: - case tok::ampequal: - case tok::caretequal: - case tok::pipeequal: return prec::Assignment; - case tok::question: return prec::Conditional; - case tok::pipepipe: return prec::LogicalOr; - case tok::ampamp: return prec::LogicalAnd; - case tok::pipe: return prec::InclusiveOr; - case tok::caret: return prec::ExclusiveOr; - case tok::amp: return prec::And; - case tok::exclaimequal: - case tok::equalequal: return prec::Equality; - case tok::lessequal: - case tok::less: - case tok::greaterequal: - case tok::greater: return prec::Relational; - case tok::lessless: - case tok::greatergreater: return prec::Shift; - case tok::plus: - case tok::minus: return prec::Additive; - case tok::percent: - case tok::slash: - case tok::star: return prec::Multiplicative; - } -} - - -/// ParseExpression - Simple precedence-based parser for binary/ternary -/// operators. -/// -/// Note: we diverge from the C99 grammar when parsing the assignment-expression -/// production. C99 specifies that the LHS of an assignment operator should be -/// parsed as a unary-expression, but consistency dictates that it be a -/// conditional-expession. In practice, the important thing here is that the -/// LHS of an assignment has to be an l-value, which productions between -/// unary-expression and conditional-expression don't produce. Because we want -/// consistency, we parse the LHS as a conditional-expression, then check for -/// l-value-ness in semantic analysis stages. -/// -/// multiplicative-expression: [C99 6.5.5] -/// cast-expression -/// multiplicative-expression '*' cast-expression -/// multiplicative-expression '/' cast-expression -/// multiplicative-expression '%' cast-expression -/// -/// additive-expression: [C99 6.5.6] -/// multiplicative-expression -/// additive-expression '+' multiplicative-expression -/// additive-expression '-' multiplicative-expression -/// -/// shift-expression: [C99 6.5.7] -/// additive-expression -/// shift-expression '<<' additive-expression -/// shift-expression '>>' additive-expression -/// -/// relational-expression: [C99 6.5.8] -/// shift-expression -/// relational-expression '<' shift-expression -/// relational-expression '>' shift-expression -/// relational-expression '<=' shift-expression -/// relational-expression '>=' shift-expression -/// -/// equality-expression: [C99 6.5.9] -/// relational-expression -/// equality-expression '==' relational-expression -/// equality-expression '!=' relational-expression -/// -/// AND-expression: [C99 6.5.10] -/// equality-expression -/// AND-expression '&' equality-expression -/// -/// exclusive-OR-expression: [C99 6.5.11] -/// AND-expression -/// exclusive-OR-expression '^' AND-expression -/// -/// inclusive-OR-expression: [C99 6.5.12] -/// exclusive-OR-expression -/// inclusive-OR-expression '|' exclusive-OR-expression -/// -/// logical-AND-expression: [C99 6.5.13] -/// inclusive-OR-expression -/// logical-AND-expression '&&' inclusive-OR-expression -/// -/// logical-OR-expression: [C99 6.5.14] -/// logical-AND-expression -/// logical-OR-expression '||' logical-AND-expression -/// -/// conditional-expression: [C99 6.5.15] -/// logical-OR-expression -/// logical-OR-expression '?' expression ':' conditional-expression -/// [GNU] logical-OR-expression '?' ':' conditional-expression -/// -/// assignment-expression: [C99 6.5.16] -/// conditional-expression -/// unary-expression assignment-operator assignment-expression -/// [C++] throw-expression [C++ 15] -/// -/// assignment-operator: one of -/// = *= /= %= += -= <<= >>= &= ^= |= -/// -/// expression: [C99 6.5.17] -/// assignment-expression -/// expression ',' assignment-expression -/// -Parser::ExprResult Parser::ParseExpression() { - if (Tok.is(tok::kw_throw)) - return ParseThrowExpression(); - - ExprResult LHS = ParseCastExpression(false); - if (LHS.isInvalid) return LHS; - - return ParseRHSOfBinaryExpression(LHS, prec::Comma); -} - -/// This routine is called when the '@' is seen and consumed. -/// Current token is an Identifier and is not a 'try'. This -/// routine is necessary to disambiguate @try-statement from, -/// for example, @encode-expression. -/// -Parser::ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { - ExprResult LHS = ParseObjCAtExpression(AtLoc); - if (LHS.isInvalid) return LHS; - - return ParseRHSOfBinaryExpression(LHS, prec::Comma); -} - -/// ParseAssignmentExpression - Parse an expr that doesn't include commas. -/// -Parser::ExprResult Parser::ParseAssignmentExpression() { - if (Tok.is(tok::kw_throw)) - return ParseThrowExpression(); - - ExprResult LHS = ParseCastExpression(false); - if (LHS.isInvalid) return LHS; - - return ParseRHSOfBinaryExpression(LHS, prec::Assignment); -} - -Parser::ExprResult Parser::ParseConstantExpression() { - ExprResult LHS = ParseCastExpression(false); - if (LHS.isInvalid) return LHS; - - return ParseRHSOfBinaryExpression(LHS, prec::Conditional); -} - -/// ParseExpressionWithLeadingIdentifier - This special purpose method is used -/// in contexts where we have already consumed an identifier (which we saved in -/// 'IdTok'), then discovered that the identifier was really the leading token -/// of part of an expression. For example, in "A[1]+B", we consumed "A" (which -/// is now in 'IdTok') and the current token is "[". -Parser::ExprResult Parser:: -ParseExpressionWithLeadingIdentifier(const Token &IdTok) { - // We know that 'IdTok' must correspond to this production: - // primary-expression: identifier - - // Let the actions module handle the identifier. - ExprResult Res = Actions.ActOnIdentifierExpr(CurScope, IdTok.getLocation(), - *IdTok.getIdentifierInfo(), - Tok.is(tok::l_paren)); - - // Because we have to parse an entire cast-expression before starting the - // ParseRHSOfBinaryExpression method (which parses any trailing binops), we - // need to handle the 'postfix-expression' rules. We do this by invoking - // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes: - Res = ParsePostfixExpressionSuffix(Res); - if (Res.isInvalid) return Res; - - // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is - // done, we know we don't have to do anything for cast-expression, because the - // only non-postfix-expression production starts with a '(' token, and we know - // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression - // to consume any trailing operators (e.g. "+" in this example) and connected - // chunks of the expression. - return ParseRHSOfBinaryExpression(Res, prec::Comma); -} - -/// ParseExpressionWithLeadingIdentifier - This special purpose method is used -/// in contexts where we have already consumed an identifier (which we saved in -/// 'IdTok'), then discovered that the identifier was really the leading token -/// of part of an assignment-expression. For example, in "A[1]+B", we consumed -/// "A" (which is now in 'IdTok') and the current token is "[". -Parser::ExprResult Parser:: -ParseAssignmentExprWithLeadingIdentifier(const Token &IdTok) { - // We know that 'IdTok' must correspond to this production: - // primary-expression: identifier - - // Let the actions module handle the identifier. - ExprResult Res = Actions.ActOnIdentifierExpr(CurScope, IdTok.getLocation(), - *IdTok.getIdentifierInfo(), - Tok.is(tok::l_paren)); - - // Because we have to parse an entire cast-expression before starting the - // ParseRHSOfBinaryExpression method (which parses any trailing binops), we - // need to handle the 'postfix-expression' rules. We do this by invoking - // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes: - Res = ParsePostfixExpressionSuffix(Res); - if (Res.isInvalid) return Res; - - // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is - // done, we know we don't have to do anything for cast-expression, because the - // only non-postfix-expression production starts with a '(' token, and we know - // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression - // to consume any trailing operators (e.g. "+" in this example) and connected - // chunks of the expression. - return ParseRHSOfBinaryExpression(Res, prec::Assignment); -} - - -/// ParseAssignmentExpressionWithLeadingStar - This special purpose method is -/// used in contexts where we have already consumed a '*' (which we saved in -/// 'StarTok'), then discovered that the '*' was really the leading token of an -/// expression. For example, in "*(int*)P+B", we consumed "*" (which is -/// now in 'StarTok') and the current token is "(". -Parser::ExprResult Parser:: -ParseAssignmentExpressionWithLeadingStar(const Token &StarTok) { - // We know that 'StarTok' must correspond to this production: - // unary-expression: unary-operator cast-expression - // where 'unary-operator' is '*'. - - // Parse the cast-expression that follows the '*'. This will parse the - // "*(int*)P" part of "*(int*)P+B". - ExprResult Res = ParseCastExpression(false); - if (Res.isInvalid) return Res; - - // Combine StarTok + Res to get the new AST for the combined expression.. - Res = Actions.ActOnUnaryOp(StarTok.getLocation(), tok::star, Res.Val); - if (Res.isInvalid) return Res; - - - // We have to parse an entire cast-expression before starting the - // ParseRHSOfBinaryExpression method (which parses any trailing binops). Since - // we know that the only production above us is the cast-expression - // production, and because the only alternative productions start with a '(' - // token (we know we had a '*'), there is no work to do to get a whole - // cast-expression. - - // At this point, the "*(int*)P" part of "*(int*)P+B" has been consumed. Once - // this is done, we can invoke ParseRHSOfBinaryExpression to consume any - // trailing operators (e.g. "+" in this example) and connected chunks of the - // assignment-expression. - return ParseRHSOfBinaryExpression(Res, prec::Assignment); -} - - -/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with -/// LHS and has a precedence of at least MinPrec. -Parser::ExprResult -Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { - unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind()); - SourceLocation ColonLoc; - - while (1) { - // If this token has a lower precedence than we are allowed to parse (e.g. - // because we are called recursively, or because the token is not a binop), - // then we are done! - if (NextTokPrec < MinPrec) - return LHS; - - // Consume the operator, saving the operator token for error reporting. - Token OpToken = Tok; - ConsumeToken(); - - // Special case handling for the ternary operator. - ExprResult TernaryMiddle(true); - if (NextTokPrec == prec::Conditional) { - if (Tok.isNot(tok::colon)) { - // Handle this production specially: - // logical-OR-expression '?' expression ':' conditional-expression - // In particular, the RHS of the '?' is 'expression', not - // 'logical-OR-expression' as we might expect. - TernaryMiddle = ParseExpression(); - if (TernaryMiddle.isInvalid) { - Actions.DeleteExpr(LHS.Val); - return TernaryMiddle; - } - } else { - // Special case handling of "X ? Y : Z" where Y is empty: - // logical-OR-expression '?' ':' conditional-expression [GNU] - TernaryMiddle = ExprResult(false); - Diag(Tok, diag::ext_gnu_conditional_expr); - } - - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon); - Diag(OpToken, diag::err_matching, "?"); - Actions.DeleteExpr(LHS.Val); - Actions.DeleteExpr(TernaryMiddle.Val); - return ExprResult(true); - } - - // Eat the colon. - ColonLoc = ConsumeToken(); - } - - // Parse another leaf here for the RHS of the operator. - ExprResult RHS = ParseCastExpression(false); - if (RHS.isInvalid) { - Actions.DeleteExpr(LHS.Val); - Actions.DeleteExpr(TernaryMiddle.Val); - return RHS; - } - - // Remember the precedence of this operator and get the precedence of the - // operator immediately to the right of the RHS. - unsigned ThisPrec = NextTokPrec; - NextTokPrec = getBinOpPrecedence(Tok.getKind()); - - // Assignment and conditional expressions are right-associative. - bool isRightAssoc = ThisPrec == prec::Conditional || - ThisPrec == prec::Assignment; - - // Get the precedence of the operator to the right of the RHS. If it binds - // more tightly with RHS than we do, evaluate it completely first. - if (ThisPrec < NextTokPrec || - (ThisPrec == NextTokPrec && isRightAssoc)) { - // If this is left-associative, only parse things on the RHS that bind - // more tightly than the current operator. If it is left-associative, it - // is okay, to bind exactly as tightly. For example, compile A=B=C=D as - // A=(B=(C=D)), where each paren is a level of recursion here. - RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec + !isRightAssoc); - if (RHS.isInvalid) { - Actions.DeleteExpr(LHS.Val); - Actions.DeleteExpr(TernaryMiddle.Val); - return RHS; - } - - NextTokPrec = getBinOpPrecedence(Tok.getKind()); - } - assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); - - if (!LHS.isInvalid) { - // Combine the LHS and RHS into the LHS (e.g. build AST). - if (TernaryMiddle.isInvalid) - LHS = Actions.ActOnBinOp(OpToken.getLocation(), OpToken.getKind(), - LHS.Val, RHS.Val); - else - LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, - LHS.Val, TernaryMiddle.Val, RHS.Val); - } else { - // We had a semantic error on the LHS. Just free the RHS and continue. - Actions.DeleteExpr(TernaryMiddle.Val); - Actions.DeleteExpr(RHS.Val); - } - } -} - -/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is -/// true, parse a unary-expression. -/// -/// cast-expression: [C99 6.5.4] -/// unary-expression -/// '(' type-name ')' cast-expression -/// -/// unary-expression: [C99 6.5.3] -/// postfix-expression -/// '++' unary-expression -/// '--' unary-expression -/// unary-operator cast-expression -/// 'sizeof' unary-expression -/// 'sizeof' '(' type-name ')' -/// [GNU] '__alignof' unary-expression -/// [GNU] '__alignof' '(' type-name ')' -/// [GNU] '&&' identifier -/// -/// unary-operator: one of -/// '&' '*' '+' '-' '~' '!' -/// [GNU] '__extension__' '__real' '__imag' -/// -/// primary-expression: [C99 6.5.1] -/// identifier -/// constant -/// string-literal -/// [C++] boolean-literal [C++ 2.13.5] -/// '(' expression ')' -/// '__func__' [C99 6.4.2.2] -/// [GNU] '__FUNCTION__' -/// [GNU] '__PRETTY_FUNCTION__' -/// [GNU] '(' compound-statement ')' -/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' -/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' -/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' -/// assign-expr ')' -/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' -/// [OBJC] '[' objc-message-expr ']' -/// [OBJC] '@selector' '(' objc-selector-arg ')' -/// [OBJC] '@protocol' '(' identifier ')' -/// [OBJC] '@encode' '(' type-name ')' -/// [OBJC] objc-string-literal -/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] -/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] -/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] -/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] -/// -/// constant: [C99 6.4.4] -/// integer-constant -/// floating-constant -/// enumeration-constant -> identifier -/// character-constant -/// -Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { - ExprResult Res; - tok::TokenKind SavedKind = Tok.getKind(); - - // This handles all of cast-expression, unary-expression, postfix-expression, - // and primary-expression. We handle them together like this for efficiency - // and to simplify handling of an expression starting with a '(' token: which - // may be one of a parenthesized expression, cast-expression, compound literal - // expression, or statement expression. - // - // If the parsed tokens consist of a primary-expression, the cases below - // call ParsePostfixExpressionSuffix to handle the postfix expression - // suffixes. Cases that cannot be followed by postfix exprs should - // return without invoking ParsePostfixExpressionSuffix. - switch (SavedKind) { - case tok::l_paren: { - // If this expression is limited to being a unary-expression, the parent can - // not start a cast expression. - ParenParseOption ParenExprType = - isUnaryExpression ? CompoundLiteral : CastExpr; - TypeTy *CastTy; - SourceLocation LParenLoc = Tok.getLocation(); - SourceLocation RParenLoc; - Res = ParseParenExpression(ParenExprType, CastTy, RParenLoc); - if (Res.isInvalid) return Res; - - switch (ParenExprType) { - case SimpleExpr: break; // Nothing else to do. - case CompoundStmt: break; // Nothing else to do. - case CompoundLiteral: - // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of - // postfix-expression exist, parse them now. - break; - case CastExpr: - // We parsed '(' type-name ')' and the thing after it wasn't a '{'. Parse - // the cast-expression that follows it next. - // TODO: For cast expression with CastTy. - Res = ParseCastExpression(false); - if (!Res.isInvalid) - Res = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc, Res.Val); - return Res; - } - - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(Res); - } - - // primary-expression - case tok::numeric_constant: - // constant: integer-constant - // constant: floating-constant - - Res = Actions.ActOnNumericConstant(Tok); - ConsumeToken(); - - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(Res); - - case tok::kw_true: - case tok::kw_false: - return ParseCXXBoolLiteral(); - - case tok::identifier: { // primary-expression: identifier - // constant: enumeration-constant - // Consume the identifier so that we can see if it is followed by a '('. - // Function designators are allowed to be undeclared (C99 6.5.1p2), so we - // need to know whether or not this identifier is a function designator or - // not. - IdentifierInfo &II = *Tok.getIdentifierInfo(); - SourceLocation L = ConsumeToken(); - Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren)); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(Res); - } - case tok::char_constant: // constant: character-constant - Res = Actions.ActOnCharacterConstant(Tok); - ConsumeToken(); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(Res); - case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] - case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] - case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] - Res = Actions.ActOnPreDefinedExpr(Tok.getLocation(), SavedKind); - ConsumeToken(); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(Res); - case tok::string_literal: // primary-expression: string-literal - case tok::wide_string_literal: - Res = ParseStringLiteralExpression(); - if (Res.isInvalid) return Res; - // This can be followed by postfix-expr pieces (e.g. "foo"[1]). - return ParsePostfixExpressionSuffix(Res); - case tok::kw___builtin_va_arg: - case tok::kw___builtin_offsetof: - case tok::kw___builtin_choose_expr: - case tok::kw___builtin_overload: - case tok::kw___builtin_types_compatible_p: - return ParseBuiltinPrimaryExpression(); - case tok::plusplus: // unary-expression: '++' unary-expression - case tok::minusminus: { // unary-expression: '--' unary-expression - SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(true); - if (!Res.isInvalid) - Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); - return Res; - } - case tok::amp: // unary-expression: '&' cast-expression - case tok::star: // unary-expression: '*' cast-expression - case tok::plus: // unary-expression: '+' cast-expression - case tok::minus: // unary-expression: '-' cast-expression - case tok::tilde: // unary-expression: '~' cast-expression - case tok::exclaim: // unary-expression: '!' cast-expression - case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] - case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] - SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false); - if (!Res.isInvalid) - Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); - return Res; - } - - case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] - // __extension__ silences extension warnings in the subexpression. - bool SavedExtWarn = Diags.getWarnOnExtensions(); - Diags.setWarnOnExtensions(false); - SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false); - if (!Res.isInvalid) - Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); - Diags.setWarnOnExtensions(SavedExtWarn); - return Res; - } - case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression - // unary-expression: 'sizeof' '(' type-name ')' - case tok::kw___alignof: // unary-expression: '__alignof' unary-expression - // unary-expression: '__alignof' '(' type-name ')' - return ParseSizeofAlignofExpression(); - case tok::ampamp: { // unary-expression: '&&' identifier - SourceLocation AmpAmpLoc = ConsumeToken(); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return ExprResult(true); - } - - Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); - Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), - Tok.getIdentifierInfo()); - ConsumeToken(); - return Res; - } - case tok::kw_const_cast: - case tok::kw_dynamic_cast: - case tok::kw_reinterpret_cast: - case tok::kw_static_cast: - return ParseCXXCasts(); - case tok::at: { - SourceLocation AtLoc = ConsumeToken(); - return ParseObjCAtExpression(AtLoc); - } - case tok::l_square: - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); - default: - Diag(Tok, diag::err_expected_expression); - return ExprResult(true); - } - - // unreachable. - abort(); -} - -/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression -/// is parsed, this method parses any suffixes that apply. -/// -/// postfix-expression: [C99 6.5.2] -/// primary-expression -/// postfix-expression '[' expression ']' -/// postfix-expression '(' argument-expression-list[opt] ')' -/// postfix-expression '.' identifier -/// postfix-expression '->' identifier -/// postfix-expression '++' -/// postfix-expression '--' -/// '(' type-name ')' '{' initializer-list '}' -/// '(' type-name ')' '{' initializer-list ',' '}' -/// -/// argument-expression-list: [C99 6.5.2] -/// argument-expression -/// argument-expression-list ',' assignment-expression -/// -Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { - - // Now that the primary-expression piece of the postfix-expression has been - // parsed, see if there are any postfix-expression pieces here. - SourceLocation Loc; - while (1) { - switch (Tok.getKind()) { - default: // Not a postfix-expression suffix. - return LHS; - case tok::l_square: { // postfix-expression: p-e '[' expression ']' - Loc = ConsumeBracket(); - ExprResult Idx = ParseExpression(); - - SourceLocation RLoc = Tok.getLocation(); - - if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square)) - LHS = Actions.ActOnArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc); - else - LHS = ExprResult(true); - - // Match the ']'. - MatchRHSPunctuation(tok::r_square, Loc); - break; - } - - case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')' - llvm::SmallVector ArgExprs; - llvm::SmallVector CommaLocs; - - Loc = ConsumeParen(); - - if (Tok.isNot(tok::r_paren)) { - while (1) { - ExprResult ArgExpr = ParseAssignmentExpression(); - if (ArgExpr.isInvalid) { - SkipUntil(tok::r_paren); - return ExprResult(true); - } else - ArgExprs.push_back(ArgExpr.Val); - - if (Tok.isNot(tok::comma)) - break; - // Move to the next argument, remember where the comma was. - CommaLocs.push_back(ConsumeToken()); - } - } - - // Match the ')'. - if (!LHS.isInvalid && Tok.is(tok::r_paren)) { - assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& - "Unexpected number of commas!"); - LHS = Actions.ActOnCallExpr(LHS.Val, Loc, &ArgExprs[0], ArgExprs.size(), - &CommaLocs[0], Tok.getLocation()); - } - - MatchRHSPunctuation(tok::r_paren, Loc); - break; - } - case tok::arrow: // postfix-expression: p-e '->' identifier - case tok::period: { // postfix-expression: p-e '.' identifier - tok::TokenKind OpKind = Tok.getKind(); - SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return ExprResult(true); - } - - if (!LHS.isInvalid) - LHS = Actions.ActOnMemberReferenceExpr(LHS.Val, OpLoc, OpKind, - Tok.getLocation(), - *Tok.getIdentifierInfo()); - ConsumeToken(); - break; - } - case tok::plusplus: // postfix-expression: postfix-expression '++' - case tok::minusminus: // postfix-expression: postfix-expression '--' - if (!LHS.isInvalid) - LHS = Actions.ActOnPostfixUnaryOp(Tok.getLocation(), Tok.getKind(), - LHS.Val); - ConsumeToken(); - break; - } - } -} - - -/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. -/// unary-expression: [C99 6.5.3] -/// 'sizeof' unary-expression -/// 'sizeof' '(' type-name ')' -/// [GNU] '__alignof' unary-expression -/// [GNU] '__alignof' '(' type-name ')' -Parser::ExprResult Parser::ParseSizeofAlignofExpression() { - assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)) && - "Not a sizeof/alignof expression!"); - Token OpTok = Tok; - ConsumeToken(); - - // If the operand doesn't start with an '(', it must be an expression. - ExprResult Operand; - if (Tok.isNot(tok::l_paren)) { - Operand = ParseCastExpression(true); - } else { - // If it starts with a '(', we know that it is either a parenthesized - // type-name, or it is a unary-expression that starts with a compound - // literal, or starts with a primary-expression that is a parenthesized - // expression. - ParenParseOption ExprType = CastExpr; - TypeTy *CastTy; - SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; - Operand = ParseParenExpression(ExprType, CastTy, RParenLoc); - - // If ParseParenExpression parsed a '(typename)' sequence only, the this is - // sizeof/alignof a type. Otherwise, it is sizeof/alignof an expression. - if (ExprType == CastExpr) - return Actions.ActOnSizeOfAlignOfTypeExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - LParenLoc, CastTy, RParenLoc); - - // If this is a parenthesized expression, it is the start of a - // unary-expression, but doesn't include any postfix pieces. Parse these - // now if present. - Operand = ParsePostfixExpressionSuffix(Operand); - } - - // If we get here, the operand to the sizeof/alignof was an expresion. - if (!Operand.isInvalid) - Operand = Actions.ActOnUnaryOp(OpTok.getLocation(), OpTok.getKind(), - Operand.Val); - return Operand; -} - -/// ParseBuiltinPrimaryExpression -/// -/// primary-expression: [C99 6.5.1] -/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' -/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' -/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' -/// assign-expr ')' -/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' -/// [CLANG] '__builtin_overload' '(' expr (',' expr)* ')' -/// -/// [GNU] offsetof-member-designator: -/// [GNU] identifier -/// [GNU] offsetof-member-designator '.' identifier -/// [GNU] offsetof-member-designator '[' expression ']' -/// -Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() { - ExprResult Res(false); - const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); - - tok::TokenKind T = Tok.getKind(); - SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. - - // All of these start with an open paren. - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName()); - return ExprResult(true); - } - - SourceLocation LParenLoc = ConsumeParen(); - // TODO: Build AST. - - switch (T) { - default: assert(0 && "Not a builtin primary expression!"); - case tok::kw___builtin_va_arg: { - ExprResult Expr = ParseAssignmentExpression(); - if (Expr.isInvalid) { - SkipUntil(tok::r_paren); - return Res; - } - - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprResult(true); - - TypeTy *Ty = ParseTypeName(); - - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - return ExprResult(true); - } - Res = Actions.ActOnVAArg(StartLoc, Expr.Val, Ty, ConsumeParen()); - break; - } - case tok::kw___builtin_offsetof: { - SourceLocation TypeLoc = Tok.getLocation(); - TypeTy *Ty = ParseTypeName(); - - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprResult(true); - - // We must have at least one identifier here. - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren); - return true; - } - - // Keep track of the various subcomponents we see. - llvm::SmallVector Comps; - - Comps.push_back(Action::OffsetOfComponent()); - Comps.back().isBrackets = false; - Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); - Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); - - while (1) { - if (Tok.is(tok::period)) { - // offsetof-member-designator: offsetof-member-designator '.' identifier - Comps.push_back(Action::OffsetOfComponent()); - Comps.back().isBrackets = false; - Comps.back().LocStart = ConsumeToken(); - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren); - return true; - } - Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); - Comps.back().LocEnd = ConsumeToken(); - - } else if (Tok.is(tok::l_square)) { - // offsetof-member-designator: offsetof-member-design '[' expression ']' - Comps.push_back(Action::OffsetOfComponent()); - Comps.back().isBrackets = true; - Comps.back().LocStart = ConsumeBracket(); - Res = ParseExpression(); - if (Res.isInvalid) { - SkipUntil(tok::r_paren); - return Res; - } - Comps.back().U.E = Res.Val; - - Comps.back().LocEnd = - MatchRHSPunctuation(tok::r_square, Comps.back().LocStart); - } else if (Tok.is(tok::r_paren)) { - Res = Actions.ActOnBuiltinOffsetOf(StartLoc, TypeLoc, Ty, &Comps[0], - Comps.size(), ConsumeParen()); - break; - } else { - // Error occurred. - return ExprResult(true); - } - } - break; - } - case tok::kw___builtin_choose_expr: { - ExprResult Cond = ParseAssignmentExpression(); - if (Cond.isInvalid) { - SkipUntil(tok::r_paren); - return Cond; - } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprResult(true); - - ExprResult Expr1 = ParseAssignmentExpression(); - if (Expr1.isInvalid) { - SkipUntil(tok::r_paren); - return Expr1; - } - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprResult(true); - - ExprResult Expr2 = ParseAssignmentExpression(); - if (Expr2.isInvalid) { - SkipUntil(tok::r_paren); - return Expr2; - } - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - return ExprResult(true); - } - Res = Actions.ActOnChooseExpr(StartLoc, Cond.Val, Expr1.Val, Expr2.Val, - ConsumeParen()); - break; - } - case tok::kw___builtin_overload: { - llvm::SmallVector ArgExprs; - llvm::SmallVector CommaLocs; - - // For each iteration through the loop look for assign-expr followed by a - // comma. If there is no comma, break and attempt to match r-paren. - if (Tok.isNot(tok::r_paren)) { - while (1) { - ExprResult ArgExpr = ParseAssignmentExpression(); - if (ArgExpr.isInvalid) { - SkipUntil(tok::r_paren); - return ExprResult(true); - } else - ArgExprs.push_back(ArgExpr.Val); - - if (Tok.isNot(tok::comma)) - break; - // Move to the next argument, remember where the comma was. - CommaLocs.push_back(ConsumeToken()); - } - } - - // Attempt to consume the r-paren - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren); - return ExprResult(true); - } - Res = Actions.ActOnOverloadExpr(&ArgExprs[0], ArgExprs.size(), - &CommaLocs[0], StartLoc, ConsumeParen()); - break; - } - case tok::kw___builtin_types_compatible_p: - TypeTy *Ty1 = ParseTypeName(); - - if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) - return ExprResult(true); - - TypeTy *Ty2 = ParseTypeName(); - - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - return ExprResult(true); - } - Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1, Ty2, ConsumeParen()); - break; - } - - // These can be followed by postfix-expr pieces because they are - // primary-expressions. - return ParsePostfixExpressionSuffix(Res); -} - -/// ParseParenExpression - This parses the unit that starts with a '(' token, -/// based on what is allowed by ExprType. The actual thing parsed is returned -/// in ExprType. -/// -/// primary-expression: [C99 6.5.1] -/// '(' expression ')' -/// [GNU] '(' compound-statement ')' (if !ParenExprOnly) -/// postfix-expression: [C99 6.5.2] -/// '(' type-name ')' '{' initializer-list '}' -/// '(' type-name ')' '{' initializer-list ',' '}' -/// cast-expression: [C99 6.5.4] -/// '(' type-name ')' cast-expression -/// -Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, - TypeTy *&CastTy, - SourceLocation &RParenLoc) { - assert(Tok.is(tok::l_paren) && "Not a paren expr!"); - SourceLocation OpenLoc = ConsumeParen(); - ExprResult Result(true); - CastTy = 0; - - if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { - Diag(Tok, diag::ext_gnu_statement_expr); - Parser::StmtResult Stmt = ParseCompoundStatement(true); - ExprType = CompoundStmt; - - // If the substmt parsed correctly, build the AST node. - if (!Stmt.isInvalid && Tok.is(tok::r_paren)) - Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.Val, Tok.getLocation()); - - } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) { - // Otherwise, this is a compound literal expression or cast expression. - TypeTy *Ty = ParseTypeName(); - - // Match the ')'. - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, OpenLoc); - - if (Tok.is(tok::l_brace)) { - if (!getLang().C99) // Compound literals don't exist in C90. - Diag(OpenLoc, diag::ext_c99_compound_literal); - Result = ParseInitializer(); - ExprType = CompoundLiteral; - if (!Result.isInvalid) - return Actions.ActOnCompoundLiteral(OpenLoc, Ty, RParenLoc, Result.Val); - } else if (ExprType == CastExpr) { - // Note that this doesn't parse the subsequence cast-expression, it just - // returns the parsed type to the callee. - ExprType = CastExpr; - CastTy = Ty; - return ExprResult(false); - } else { - Diag(Tok, diag::err_expected_lbrace_in_compound_literal); - return ExprResult(true); - } - return Result; - } else { - Result = ParseExpression(); - ExprType = SimpleExpr; - if (!Result.isInvalid && Tok.is(tok::r_paren)) - Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.Val); - } - - // Match the ')'. - if (Result.isInvalid) - SkipUntil(tok::r_paren); - else { - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, OpenLoc); - } - - return Result; -} - -/// ParseStringLiteralExpression - This handles the various token types that -/// form string literals, and also handles string concatenation [C99 5.1.1.2, -/// translation phase #6]. -/// -/// primary-expression: [C99 6.5.1] -/// string-literal -Parser::ExprResult Parser::ParseStringLiteralExpression() { - assert(isTokenStringLiteral() && "Not a string literal!"); - - // String concat. Note that keywords like __func__ and __FUNCTION__ are not - // considered to be strings for concatenation purposes. - llvm::SmallVector StringToks; - - do { - StringToks.push_back(Tok); - ConsumeStringToken(); - } while (isTokenStringLiteral()); - - // Pass the set of string tokens, ready for concatenation, to the actions. - return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); -} diff --git a/clang/Parse/ParseExprCXX.cpp b/clang/Parse/ParseExprCXX.cpp deleted file mode 100644 index 6b42fb5b089..00000000000 --- a/clang/Parse/ParseExprCXX.cpp +++ /dev/null @@ -1,99 +0,0 @@ -//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Expression parsing implementation for C++. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/Diagnostic.h" -#include "clang/Parse/Parser.h" -using namespace clang; - -/// ParseCXXCasts - This handles the various ways to cast expressions to another -/// type. -/// -/// postfix-expression: [C++ 5.2p1] -/// 'dynamic_cast' '<' type-name '>' '(' expression ')' -/// 'static_cast' '<' type-name '>' '(' expression ')' -/// 'reinterpret_cast' '<' type-name '>' '(' expression ')' -/// 'const_cast' '<' type-name '>' '(' expression ')' -/// -Parser::ExprResult Parser::ParseCXXCasts() { - tok::TokenKind Kind = Tok.getKind(); - const char *CastName = 0; // For error messages - - switch (Kind) { - default: assert(0 && "Unknown C++ cast!"); abort(); - case tok::kw_const_cast: CastName = "const_cast"; break; - case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; - case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; - case tok::kw_static_cast: CastName = "static_cast"; break; - } - - SourceLocation OpLoc = ConsumeToken(); - SourceLocation LAngleBracketLoc = Tok.getLocation(); - - if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) - return ExprResult(true); - - TypeTy *CastTy = ParseTypeName(); - SourceLocation RAngleBracketLoc = Tok.getLocation(); - - if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) { - Diag(LAngleBracketLoc, diag::err_matching, "<"); - return ExprResult(true); - } - - SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, CastName); - return ExprResult(true); - } - - ExprResult Result = ParseSimpleParenExpression(RParenLoc); - - if (!Result.isInvalid) - Result = Actions.ActOnCXXCasts(OpLoc, Kind, - LAngleBracketLoc, CastTy, RAngleBracketLoc, - LParenLoc, Result.Val, RParenLoc); - - return Result; -} - -/// ParseCXXBoolLiteral - This handles the C++ Boolean literals. -/// -/// boolean-literal: [C++ 2.13.5] -/// 'true' -/// 'false' -Parser::ExprResult Parser::ParseCXXBoolLiteral() { - tok::TokenKind Kind = Tok.getKind(); - return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind); -} - -/// ParseThrowExpression - This handles the C++ throw expression. -/// -/// throw-expression: [C++ 15] -/// 'throw' assignment-expression[opt] -Parser::ExprResult Parser::ParseThrowExpression() { - assert(Tok.is(tok::kw_throw) && "Not throw!"); - - ExprResult Expr; - - SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. - // FIXME: Anything that isn't an assignment-expression should bail out now. - if (Tok.is(tok::semi) || Tok.is(tok::r_paren) || Tok.is(tok::colon) || - Tok.is(tok::comma)) - return Actions.ActOnCXXThrow(ThrowLoc); - - Expr = ParseAssignmentExpression(); - if (!Expr.isInvalid) - Expr = Actions.ActOnCXXThrow(ThrowLoc, Expr.Val); - return Expr; -} diff --git a/clang/Parse/ParseInit.cpp b/clang/Parse/ParseInit.cpp deleted file mode 100644 index 45cf86e5b44..00000000000 --- a/clang/Parse/ParseInit.cpp +++ /dev/null @@ -1,227 +0,0 @@ -//===--- ParseInit.cpp - Initializer Parsing ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements initializer parsing as specified by C99 6.7.8. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/SmallString.h" -using namespace clang; - - -/// MayBeDesignationStart - Return true if this token might be the start of a -/// designator. -static bool MayBeDesignationStart(tok::TokenKind K) { - switch (K) { - default: return false; - case tok::period: // designator: '.' identifier - case tok::l_square: // designator: array-designator - case tok::identifier: // designation: identifier ':' - return true; - } -} - -/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production -/// checking to see if the token stream starts with a designator. -/// -/// designation: -/// designator-list '=' -/// [GNU] array-designator -/// [GNU] identifier ':' -/// -/// designator-list: -/// designator -/// designator-list designator -/// -/// designator: -/// array-designator -/// '.' identifier -/// -/// array-designator: -/// '[' constant-expression ']' -/// [GNU] '[' constant-expression '...' constant-expression ']' -/// -/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an -/// initializer. We need to consider this case when parsing array designators. -/// -Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() { - // Parse each designator in the designator list until we find an initializer. - while (1) { - switch (Tok.getKind()) { - case tok::equal: - // We read some number (at least one due to the grammar we implemented) - // of designators and found an '=' sign. The following tokens must be - // the initializer. - ConsumeToken(); - return ParseInitializer(); - - default: { - // We read some number (at least one due to the grammar we implemented) - // of designators and found something that isn't an = or an initializer. - // If we have exactly one array designator [TODO CHECK], this is the GNU - // 'designation: array-designator' extension. Otherwise, it is a parse - // error. - SourceLocation Loc = Tok.getLocation(); - ExprResult Init = ParseInitializer(); - if (Init.isInvalid) return Init; - - Diag(Tok, diag::ext_gnu_missing_equal_designator); - return Init; - } - case tok::period: - // designator: '.' identifier - ConsumeToken(); - if (ExpectAndConsume(tok::identifier, diag::err_expected_ident)) - return ExprResult(true); - break; - - case tok::l_square: { - // array-designator: '[' constant-expression ']' - // array-designator: '[' constant-expression '...' constant-expression ']' - // When designation is empty, this can be '[' objc-message-expr ']'. Note - // that we also have the case of [4][foo bar], which is the gnu designator - // extension + objc message send. - SourceLocation StartLoc = ConsumeBracket(); - - // If Objective-C is enabled and this is a typename or other identifier - // receiver, parse this as a message send expression. - if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) { - // FIXME: Emit ext_gnu_missing_equal_designator for inits like - // [4][foo bar]. - IdentifierInfo *Name = Tok.getIdentifierInfo(); - ConsumeToken(); - ExprResult R = ParseObjCMessageExpressionBody(StartLoc, Name, 0); - return ParsePostfixExpressionSuffix(R); - } - - // Note that we parse this as an assignment expression, not a constant - // expression (allowing *=, =, etc) to handle the objc case. Sema needs - // to validate that the expression is a constant. - ExprResult Idx = ParseAssignmentExpression(); - if (Idx.isInvalid) { - SkipUntil(tok::r_square); - return Idx; - } - - // Given an expression, we could either have a designator (if the next - // tokens are '...' or ']' or an objc message send. If this is an objc - // message send, handle it now. - if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && - Tok.isNot(tok::r_square)) { - // FIXME: Emit ext_gnu_missing_equal_designator for inits like - // [4][foo bar]. - ExprResult R = ParseObjCMessageExpressionBody(StartLoc, 0, Idx.Val); - return ParsePostfixExpressionSuffix(R); - } - - // Handle the gnu array range extension. - if (Tok.is(tok::ellipsis)) { - Diag(Tok, diag::ext_gnu_array_range); - ConsumeToken(); - - ExprResult RHS = ParseConstantExpression(); - if (RHS.isInvalid) { - SkipUntil(tok::r_square); - return RHS; - } - } - - MatchRHSPunctuation(tok::r_square, StartLoc); - break; - } - case tok::identifier: { - // Due to the GNU "designation: identifier ':'" extension, we don't know - // whether something starting with an identifier is an - // assignment-expression or if it is an old-style structure field - // designator. - // TODO: Check that this is the first designator. - Token Ident = Tok; - ConsumeToken(); - - // If this is the gross GNU extension, handle it now. - if (Tok.is(tok::colon)) { - Diag(Ident, diag::ext_gnu_old_style_field_designator); - ConsumeToken(); - return ParseInitializer(); - } - - // Otherwise, we just consumed the first token of an expression. Parse - // the rest of it now. - return ParseAssignmentExprWithLeadingIdentifier(Ident); - } - } - } -} - - -/// ParseInitializer -/// initializer: [C99 6.7.8] -/// assignment-expression -/// '{' initializer-list '}' -/// '{' initializer-list ',' '}' -/// [GNU] '{' '}' -/// -/// initializer-list: -/// designation[opt] initializer -/// initializer-list ',' designation[opt] initializer -/// -Parser::ExprResult Parser::ParseInitializer() { - if (Tok.isNot(tok::l_brace)) - return ParseAssignmentExpression(); - - SourceLocation LBraceLoc = ConsumeBrace(); - - // We support empty initializers, but tell the user that they aren't using - // C99-clean code. - if (Tok.is(tok::r_brace)) { - Diag(LBraceLoc, diag::ext_gnu_empty_initializer); - // Match the '}'. - return Actions.ActOnInitList(LBraceLoc, 0, 0, ConsumeBrace()); - } - llvm::SmallVector InitExprs; - bool InitExprsOk = true; - - while (1) { - // Parse: designation[opt] initializer - - // If we know that this cannot be a designation, just parse the nested - // initializer directly. - ExprResult SubElt; - if (!MayBeDesignationStart(Tok.getKind())) - SubElt = ParseInitializer(); - else - SubElt = ParseInitializerWithPotentialDesignator(); - - // If we couldn't parse the subelement, bail out. - if (SubElt.isInvalid) { - InitExprsOk = false; - SkipUntil(tok::r_brace, false, true); - break; - } else - InitExprs.push_back(SubElt.Val); - - // If we don't have a comma continued list, we're done. - if (Tok.isNot(tok::comma)) break; - - // FIXME: save comma locations. - ConsumeToken(); - - // Handle trailing comma. - if (Tok.is(tok::r_brace)) break; - } - if (InitExprsOk && Tok.is(tok::r_brace)) - return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(), - ConsumeBrace()); - // Match the '}'. - MatchRHSPunctuation(tok::r_brace, LBraceLoc); - return ExprResult(true); // an error occurred. -} - diff --git a/clang/Parse/ParseObjc.cpp b/clang/Parse/ParseObjc.cpp deleted file mode 100644 index 77d2adbd320..00000000000 --- a/clang/Parse/ParseObjc.cpp +++ /dev/null @@ -1,1578 +0,0 @@ -//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Objective-C portions of the Parser interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/SmallVector.h" -using namespace clang; - - -/// ParseExternalDeclaration: -/// external-declaration: [C99 6.9] -/// [OBJC] objc-class-definition -/// [OBJC] objc-class-declaration -/// [OBJC] objc-alias-declaration -/// [OBJC] objc-protocol-definition -/// [OBJC] objc-method-definition -/// [OBJC] '@' 'end' -Parser::DeclTy *Parser::ParseObjCAtDirectives() { - SourceLocation AtLoc = ConsumeToken(); // the "@" - - switch (Tok.getObjCKeywordID()) { - case tok::objc_class: - return ParseObjCAtClassDeclaration(AtLoc); - case tok::objc_interface: - return ParseObjCAtInterfaceDeclaration(AtLoc); - case tok::objc_protocol: - return ParseObjCAtProtocolDeclaration(AtLoc); - case tok::objc_implementation: - return ParseObjCAtImplementationDeclaration(AtLoc); - case tok::objc_end: - return ParseObjCAtEndDeclaration(AtLoc); - case tok::objc_compatibility_alias: - return ParseObjCAtAliasDeclaration(AtLoc); - case tok::objc_synthesize: - return ParseObjCPropertySynthesize(AtLoc); - case tok::objc_dynamic: - return ParseObjCPropertyDynamic(AtLoc); - default: - Diag(AtLoc, diag::err_unexpected_at); - SkipUntil(tok::semi); - return 0; - } -} - -/// -/// objc-class-declaration: -/// '@' 'class' identifier-list ';' -/// -Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { - ConsumeToken(); // the identifier "class" - llvm::SmallVector ClassNames; - - while (1) { - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::semi); - return 0; - } - ClassNames.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); - - if (Tok.isNot(tok::comma)) - break; - - ConsumeToken(); - } - - // Consume the ';'. - if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) - return 0; - - return Actions.ActOnForwardClassDeclaration(atLoc, - &ClassNames[0], ClassNames.size()); -} - -/// -/// objc-interface: -/// objc-class-interface-attributes[opt] objc-class-interface -/// objc-category-interface -/// -/// objc-class-interface: -/// '@' 'interface' identifier objc-superclass[opt] -/// objc-protocol-refs[opt] -/// objc-class-instance-variables[opt] -/// objc-interface-decl-list -/// @end -/// -/// objc-category-interface: -/// '@' 'interface' identifier '(' identifier[opt] ')' -/// objc-protocol-refs[opt] -/// objc-interface-decl-list -/// @end -/// -/// objc-superclass: -/// ':' identifier -/// -/// objc-class-interface-attributes: -/// __attribute__((visibility("default"))) -/// __attribute__((visibility("hidden"))) -/// __attribute__((deprecated)) -/// __attribute__((unavailable)) -/// __attribute__((objc_exception)) - used by NSException on 64-bit -/// -Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( - SourceLocation atLoc, AttributeList *attrList) { - assert(Tok.isObjCAtKeyword(tok::objc_interface) && - "ParseObjCAtInterfaceDeclaration(): Expected @interface"); - ConsumeToken(); // the "interface" identifier - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing class or category name. - return 0; - } - // We have a class or category name - consume it. - IdentifierInfo *nameId = Tok.getIdentifierInfo(); - SourceLocation nameLoc = ConsumeToken(); - - if (Tok.is(tok::l_paren)) { // we have a category. - SourceLocation lparenLoc = ConsumeParen(); - SourceLocation categoryLoc, rparenLoc; - IdentifierInfo *categoryId = 0; - llvm::SmallVector ProtocolRefs; - - // For ObjC2, the category name is optional (not an error). - if (Tok.is(tok::identifier)) { - categoryId = Tok.getIdentifierInfo(); - categoryLoc = ConsumeToken(); - } else if (!getLang().ObjC2) { - Diag(Tok, diag::err_expected_ident); // missing category name. - return 0; - } - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren, false); // don't stop at ';' - return 0; - } - rparenLoc = ConsumeParen(); - SourceLocation endProtoLoc; - // Next, we need to check for any protocol references. - if (Tok.is(tok::less)) { - if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc)) - return 0; - } - if (attrList) // categories don't support attributes. - Diag(Tok, diag::err_objc_no_attributes_on_category); - - DeclTy *CategoryType = Actions.ActOnStartCategoryInterface(atLoc, - nameId, nameLoc, categoryId, categoryLoc, - &ProtocolRefs[0], ProtocolRefs.size(), - endProtoLoc); - - ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); - - // The @ sign was already consumed by ParseObjCInterfaceDeclList(). - if (Tok.isObjCAtKeyword(tok::objc_end)) { - ConsumeToken(); // the "end" identifier - return CategoryType; - } - Diag(Tok, diag::err_objc_missing_end); - return 0; - } - // Parse a class interface. - IdentifierInfo *superClassId = 0; - SourceLocation superClassLoc; - - if (Tok.is(tok::colon)) { // a super class is specified. - ConsumeToken(); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing super class name. - return 0; - } - superClassId = Tok.getIdentifierInfo(); - superClassLoc = ConsumeToken(); - } - // Next, we need to check for any protocol references. - llvm::SmallVector ProtocolRefs; - SourceLocation endProtoLoc; - if (Tok.is(tok::less)) { - if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc)) - return 0; - } - DeclTy *ClsType = Actions.ActOnStartClassInterface( - atLoc, nameId, nameLoc, - superClassId, superClassLoc, &ProtocolRefs[0], - ProtocolRefs.size(), endProtoLoc, attrList); - - if (Tok.is(tok::l_brace)) - ParseObjCClassInstanceVariables(ClsType, atLoc); - - ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); - - // The @ sign was already consumed by ParseObjCInterfaceDeclList(). - if (Tok.isObjCAtKeyword(tok::objc_end)) { - ConsumeToken(); // the "end" identifier - return ClsType; - } - Diag(Tok, diag::err_objc_missing_end); - return 0; -} - -/// objc-interface-decl-list: -/// empty -/// objc-interface-decl-list objc-property-decl [OBJC2] -/// objc-interface-decl-list objc-method-requirement [OBJC2] -/// objc-interface-decl-list objc-method-proto ';' -/// objc-interface-decl-list declaration -/// objc-interface-decl-list ';' -/// -/// objc-method-requirement: [OBJC2] -/// @required -/// @optional -/// -void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl, - tok::ObjCKeywordKind contextKey) { - llvm::SmallVector allMethods; - llvm::SmallVector allProperties; - tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; - SourceLocation AtEndLoc; - - while (1) { - if (Tok.is(tok::at)) { - SourceLocation AtLoc = ConsumeToken(); // the "@" - tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID(); - - if (ocKind == tok::objc_end) { // terminate list - AtEndLoc = AtLoc; - break; - } else if (ocKind == tok::objc_required) { // protocols only - ConsumeToken(); - MethodImplKind = ocKind; - if (contextKey != tok::objc_protocol) - Diag(AtLoc, diag::err_objc_protocol_required); - } else if (ocKind == tok::objc_optional) { // protocols only - ConsumeToken(); - MethodImplKind = ocKind; - if (contextKey != tok::objc_protocol) - Diag(AtLoc, diag::err_objc_protocol_optional); - } else if (ocKind == tok::objc_property) { - allProperties.push_back(ParseObjCPropertyDecl(interfaceDecl, AtLoc)); - continue; - } else { - Diag(Tok, diag::err_objc_illegal_interface_qual); - ConsumeToken(); - } - } - if (Tok.is(tok::minus) || Tok.is(tok::plus)) { - DeclTy *methodPrototype = - ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); - allMethods.push_back(methodPrototype); - // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for - // method definitions. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after,"method proto"); - continue; - } - else if (Tok.is(tok::at)) - continue; - - if (Tok.is(tok::semi)) - ConsumeToken(); - else if (Tok.is(tok::eof)) - break; - else { - // FIXME: as the name implies, this rule allows function definitions. - // We could pass a flag or check for functions during semantic analysis. - ParseDeclarationOrFunctionDefinition(); - } - } - /// Insert collected methods declarations into the @interface object. - Actions.ActOnAtEnd(AtEndLoc, interfaceDecl, &allMethods[0], allMethods.size(), - &allProperties[0], allProperties.size()); -} - -/// Parse property attribute declarations. -/// -/// property-attr-decl: '(' property-attrlist ')' -/// property-attrlist: -/// property-attribute -/// property-attrlist ',' property-attribute -/// property-attribute: -/// getter '=' identifier -/// setter '=' identifier ':' -/// readonly -/// readwrite -/// assign -/// retain -/// copy -/// nonatomic -/// -void Parser::ParseObjCPropertyAttribute (ObjCDeclSpec &DS) { - SourceLocation loc = ConsumeParen(); // consume '(' - while (isObjCPropertyAttribute()) { - const IdentifierInfo *II = Tok.getIdentifierInfo(); - // getter/setter require extra treatment. - if (II == ObjCPropertyAttrs[objc_getter] || - II == ObjCPropertyAttrs[objc_setter]) { - // skip getter/setter part. - SourceLocation loc = ConsumeToken(); - if (Tok.is(tok::equal)) { - loc = ConsumeToken(); - if (Tok.is(tok::identifier)) { - if (II == ObjCPropertyAttrs[objc_setter]) { - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); - DS.setSetterName(Tok.getIdentifierInfo()); - loc = ConsumeToken(); // consume method name - if (Tok.isNot(tok::colon)) { - Diag(loc, diag::err_expected_colon); - SkipUntil(tok::r_paren,true,true); - break; - } - } - else { - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); - DS.setGetterName(Tok.getIdentifierInfo()); - } - } - else { - Diag(loc, diag::err_expected_ident); - SkipUntil(tok::r_paren,true,true); - break; - } - } - else { - Diag(loc, diag::err_objc_expected_equal); - SkipUntil(tok::r_paren,true,true); - break; - } - } - - else if (II == ObjCPropertyAttrs[objc_readonly]) - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly); - else if (II == ObjCPropertyAttrs[objc_assign]) - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign); - else if (II == ObjCPropertyAttrs[objc_readwrite]) - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite); - else if (II == ObjCPropertyAttrs[objc_retain]) - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain); - else if (II == ObjCPropertyAttrs[objc_copy]) - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy); - else if (II == ObjCPropertyAttrs[objc_nonatomic]) - DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic); - - ConsumeToken(); // consume last attribute token - if (Tok.is(tok::comma)) { - loc = ConsumeToken(); - continue; - } - if (Tok.is(tok::r_paren)) - break; - Diag(loc, diag::err_expected_rparen); - SkipUntil(tok::semi); - return; - } - if (Tok.is(tok::r_paren)) - ConsumeParen(); - else { - Diag(loc, diag::err_objc_expected_property_attr); - SkipUntil(tok::r_paren); // recover from error inside attribute list - } -} - -/// Main routine to parse property declaration. -/// -/// @property property-attr-decl[opt] property-component-decl ';' -/// -Parser::DeclTy *Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl, - SourceLocation AtLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_property) && - "ParseObjCPropertyDecl(): Expected @property"); - ObjCDeclSpec DS; - ConsumeToken(); // the "property" identifier - // Parse property attribute list, if any. - if (Tok.is(tok::l_paren)) { - // property has attribute list. - ParseObjCPropertyAttribute(DS); - } - // Parse declaration portion of @property. - llvm::SmallVector PropertyDecls; - ParseStructDeclaration(interfaceDecl, PropertyDecls); - if (Tok.is(tok::semi)) - ConsumeToken(); - else { - Diag(Tok, diag::err_expected_semi_decl_list); - SkipUntil(tok::r_brace, true, true); - } - return Actions.ActOnAddObjCProperties(AtLoc, - &PropertyDecls[0], PropertyDecls.size(), DS); -} - -/// objc-method-proto: -/// objc-instance-method objc-method-decl objc-method-attributes[opt] -/// objc-class-method objc-method-decl objc-method-attributes[opt] -/// -/// objc-instance-method: '-' -/// objc-class-method: '+' -/// -/// objc-method-attributes: [OBJC2] -/// __attribute__((deprecated)) -/// -Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl, - tok::ObjCKeywordKind MethodImplKind) { - assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); - - tok::TokenKind methodType = Tok.getKind(); - SourceLocation mLoc = ConsumeToken(); - - DeclTy *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl, MethodImplKind); - // Since this rule is used for both method declarations and definitions, - // the caller is (optionally) responsible for consuming the ';'. - return MDecl; -} - -/// objc-selector: -/// identifier -/// one of -/// enum struct union if else while do for switch case default -/// break continue return goto asm sizeof typeof __alignof -/// unsigned long const short volatile signed restrict _Complex -/// in out inout bycopy byref oneway int char float double void _Bool -/// -IdentifierInfo *Parser::ParseObjCSelector(SourceLocation &SelectorLoc) { - switch (Tok.getKind()) { - default: - return 0; - case tok::identifier: - case tok::kw_typeof: - case tok::kw___alignof: - case tok::kw_auto: - case tok::kw_break: - case tok::kw_case: - case tok::kw_char: - case tok::kw_const: - case tok::kw_continue: - case tok::kw_default: - case tok::kw_do: - case tok::kw_double: - case tok::kw_else: - case tok::kw_enum: - case tok::kw_extern: - case tok::kw_float: - case tok::kw_for: - case tok::kw_goto: - case tok::kw_if: - case tok::kw_inline: - case tok::kw_int: - case tok::kw_long: - case tok::kw_register: - case tok::kw_restrict: - case tok::kw_return: - case tok::kw_short: - case tok::kw_signed: - case tok::kw_sizeof: - case tok::kw_static: - case tok::kw_struct: - case tok::kw_switch: - case tok::kw_typedef: - case tok::kw_union: - case tok::kw_unsigned: - case tok::kw_void: - case tok::kw_volatile: - case tok::kw_while: - case tok::kw_bool: - case tok::kw__Bool: - case tok::kw__Complex: - IdentifierInfo *II = Tok.getIdentifierInfo(); - SelectorLoc = ConsumeToken(); - return II; - } -} - -/// property-attrlist: one of -/// readonly getter setter assign retain copy nonatomic -/// -bool Parser::isObjCPropertyAttribute() { - if (Tok.is(tok::identifier)) { - const IdentifierInfo *II = Tok.getIdentifierInfo(); - for (unsigned i = 0; i < objc_NumAttrs; ++i) - if (II == ObjCPropertyAttrs[i]) return true; - } - return false; -} - -/// objc-for-collection-in: 'in' -/// -bool Parser::isTokIdentifier_in() const { - // FIXME: May have to do additional look-ahead to only allow for - // valid tokens following an 'in'; such as an identifier, unary operators, - // '[' etc. - return (getLang().ObjC2 && Tok.is(tok::identifier) && - Tok.getIdentifierInfo() == ObjCForCollectionInKW); -} - -/// ParseObjCTypeQualifierList - This routine parses the objective-c's type -/// qualifier list and builds their bitmask representation in the input -/// argument. -/// -/// objc-type-qualifiers: -/// objc-type-qualifier -/// objc-type-qualifiers objc-type-qualifier -/// -void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { - while (1) { - if (Tok.isNot(tok::identifier)) - return; - - const IdentifierInfo *II = Tok.getIdentifierInfo(); - for (unsigned i = 0; i != objc_NumQuals; ++i) { - if (II != ObjCTypeQuals[i]) - continue; - - ObjCDeclSpec::ObjCDeclQualifier Qual; - switch (i) { - default: assert(0 && "Unknown decl qualifier"); - case objc_in: Qual = ObjCDeclSpec::DQ_In; break; - case objc_out: Qual = ObjCDeclSpec::DQ_Out; break; - case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break; - case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break; - case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break; - case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break; - } - DS.setObjCDeclQualifier(Qual); - ConsumeToken(); - II = 0; - break; - } - - // If this wasn't a recognized qualifier, bail out. - if (II) return; - } -} - -/// objc-type-name: -/// '(' objc-type-qualifiers[opt] type-name ')' -/// '(' objc-type-qualifiers[opt] ')' -/// -Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { - assert(Tok.is(tok::l_paren) && "expected ("); - - SourceLocation LParenLoc = ConsumeParen(), RParenLoc; - TypeTy *Ty = 0; - - // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS); - - if (isTypeSpecifierQualifier()) { - Ty = ParseTypeName(); - // FIXME: back when Sema support is in place... - // assert(Ty && "Parser::ParseObjCTypeName(): missing type"); - } - if (Tok.isNot(tok::r_paren)) { - MatchRHSPunctuation(tok::r_paren, LParenLoc); - return 0; // FIXME: decide how we want to handle this error... - } - RParenLoc = ConsumeParen(); - return Ty; -} - -/// objc-method-decl: -/// objc-selector -/// objc-keyword-selector objc-parmlist[opt] -/// objc-type-name objc-selector -/// objc-type-name objc-keyword-selector objc-parmlist[opt] -/// -/// objc-keyword-selector: -/// objc-keyword-decl -/// objc-keyword-selector objc-keyword-decl -/// -/// objc-keyword-decl: -/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier -/// objc-selector ':' objc-keyword-attributes[opt] identifier -/// ':' objc-type-name objc-keyword-attributes[opt] identifier -/// ':' objc-keyword-attributes[opt] identifier -/// -/// objc-parmlist: -/// objc-parms objc-ellipsis[opt] -/// -/// objc-parms: -/// objc-parms , parameter-declaration -/// -/// objc-ellipsis: -/// , ... -/// -/// objc-keyword-attributes: [OBJC2] -/// __attribute__((unused)) -/// -Parser::DeclTy *Parser::ParseObjCMethodDecl(SourceLocation mLoc, - tok::TokenKind mType, - DeclTy *IDecl, - tok::ObjCKeywordKind MethodImplKind) -{ - // Parse the return type. - TypeTy *ReturnType = 0; - ObjCDeclSpec DSRet; - if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet); - SourceLocation selLoc; - IdentifierInfo *SelIdent = ParseObjCSelector(selLoc); - if (Tok.isNot(tok::colon)) { - if (!SelIdent) { - Diag(Tok, diag::err_expected_ident); // missing selector name. - // FIXME: this creates a unary selector with a null identifier, is this - // ok?? Maybe we should skip to the next semicolon or something. - } - - // If attributes exist after the method, parse them. - AttributeList *MethodAttrs = 0; - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseAttributes(); - - Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), - mType, IDecl, DSRet, ReturnType, Sel, - 0, 0, 0, MethodAttrs, MethodImplKind); - } - - llvm::SmallVector KeyIdents; - llvm::SmallVector KeyTypes; - llvm::SmallVector ArgTypeQuals; - llvm::SmallVector ArgNames; - - Action::TypeTy *TypeInfo; - while (1) { - KeyIdents.push_back(SelIdent); - - // Each iteration parses a single keyword argument. - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon); - break; - } - ConsumeToken(); // Eat the ':'. - ObjCDeclSpec DSType; - if (Tok.is(tok::l_paren)) { // Parse the argument type. - TypeInfo = ParseObjCTypeName(DSType); - } - else - TypeInfo = 0; - KeyTypes.push_back(TypeInfo); - ArgTypeQuals.push_back(DSType); - - // If attributes exist before the argument name, parse them. - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - ParseAttributes(); // FIXME: pass attributes through. - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing argument name. - break; - } - ArgNames.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); // Eat the identifier. - - // Check for another keyword selector. - SourceLocation Loc; - SelIdent = ParseObjCSelector(Loc); - if (!SelIdent && Tok.isNot(tok::colon)) - break; - // We have a selector or a colon, continue parsing. - } - - bool isVariadic = false; - - // Parse the (optional) parameter list. - while (Tok.is(tok::comma)) { - ConsumeToken(); - if (Tok.is(tok::ellipsis)) { - isVariadic = true; - ConsumeToken(); - break; - } - // FIXME: implement this... - // Parse the c-style argument declaration-specifier. - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - // Parse the declarator. - Declarator ParmDecl(DS, Declarator::PrototypeContext); - ParseDeclarator(ParmDecl); - } - - // FIXME: Add support for optional parmameter list... - // If attributes exist after the method, parse them. - AttributeList *MethodAttrs = 0; - if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseAttributes(); - - Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), - &KeyIdents[0]); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), - mType, IDecl, DSRet, ReturnType, Sel, - &ArgTypeQuals[0], &KeyTypes[0], - &ArgNames[0], MethodAttrs, - MethodImplKind, isVariadic); -} - -/// CmpProtocolVals - Comparison predicate for sorting protocols. -static bool CmpProtocolVals(const IdentifierInfo* const& lhs, - const IdentifierInfo* const& rhs) { - return strcmp(lhs->getName(), rhs->getName()) < 0; -} - -/// objc-protocol-refs: -/// '<' identifier-list '>' -/// -bool Parser::ParseObjCProtocolReferences( - llvm::SmallVectorImpl &ProtocolRefs, SourceLocation &endLoc) -{ - assert(Tok.is(tok::less) && "expected <"); - - ConsumeToken(); // the "<" - - while (1) { - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::greater); - return true; - } - ProtocolRefs.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); - - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); - } - - // Sort protocols, keyed by name. - // Later on, we remove duplicates. - std::stable_sort(ProtocolRefs.begin(), ProtocolRefs.end(), CmpProtocolVals); - - // Make protocol names unique. - ProtocolRefs.erase(std::unique(ProtocolRefs.begin(), ProtocolRefs.end()), - ProtocolRefs.end()); - // Consume the '>'. - if (Tok.is(tok::greater)) { - endLoc = ConsumeAnyToken(); - return false; - } - Diag(Tok, diag::err_expected_greater); - return true; -} - -/// objc-class-instance-variables: -/// '{' objc-instance-variable-decl-list[opt] '}' -/// -/// objc-instance-variable-decl-list: -/// objc-visibility-spec -/// objc-instance-variable-decl ';' -/// ';' -/// objc-instance-variable-decl-list objc-visibility-spec -/// objc-instance-variable-decl-list objc-instance-variable-decl ';' -/// objc-instance-variable-decl-list ';' -/// -/// objc-visibility-spec: -/// @private -/// @protected -/// @public -/// @package [OBJC2] -/// -/// objc-instance-variable-decl: -/// struct-declaration -/// -void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, - SourceLocation atLoc) { - assert(Tok.is(tok::l_brace) && "expected {"); - llvm::SmallVector IvarDecls; - llvm::SmallVector AllIvarDecls; - llvm::SmallVector AllVisibilities; - - SourceLocation LBraceLoc = ConsumeBrace(); // the "{" - - tok::ObjCKeywordKind visibility = tok::objc_private; - // While we still have something to read, read the instance variables. - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - // Each iteration of this loop reads one objc-instance-variable-decl. - - // Check for extraneous top-level semicolon. - if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi); - ConsumeToken(); - continue; - } - // Set the default visibility to private. - if (Tok.is(tok::at)) { // parse objc-visibility-spec - ConsumeToken(); // eat the @ sign - switch (Tok.getObjCKeywordID()) { - case tok::objc_private: - case tok::objc_public: - case tok::objc_protected: - case tok::objc_package: - visibility = Tok.getObjCKeywordID(); - ConsumeToken(); - continue; - default: - Diag(Tok, diag::err_objc_illegal_visibility_spec); - ConsumeToken(); - continue; - } - } - ParseStructDeclaration(interfaceDecl, IvarDecls); - for (unsigned i = 0; i < IvarDecls.size(); i++) { - AllIvarDecls.push_back(IvarDecls[i]); - AllVisibilities.push_back(visibility); - } - IvarDecls.clear(); - - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else if (Tok.is(tok::r_brace)) { - Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list); - break; - } else { - Diag(Tok, diag::err_expected_semi_decl_list); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - } - } - SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - // Call ActOnFields() even if we don't have any decls. This is useful - // for code rewriting tools that need to be aware of the empty list. - Actions.ActOnFields(CurScope, atLoc, interfaceDecl, - &AllIvarDecls[0], AllIvarDecls.size(), - LBraceLoc, RBraceLoc, &AllVisibilities[0]); - return; -} - -/// objc-protocol-declaration: -/// objc-protocol-definition -/// objc-protocol-forward-reference -/// -/// objc-protocol-definition: -/// @protocol identifier -/// objc-protocol-refs[opt] -/// objc-interface-decl-list -/// @end -/// -/// objc-protocol-forward-reference: -/// @protocol identifier-list ';' -/// -/// "@protocol identifier ;" should be resolved as "@protocol -/// identifier-list ;": objc-interface-decl-list may not start with a -/// semicolon in the first alternative if objc-protocol-refs are omitted. - -Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_protocol) && - "ParseObjCAtProtocolDeclaration(): Expected @protocol"); - ConsumeToken(); // the "protocol" identifier - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing protocol name. - return 0; - } - // Save the protocol name, then consume it. - IdentifierInfo *protocolName = Tok.getIdentifierInfo(); - SourceLocation nameLoc = ConsumeToken(); - - llvm::SmallVector ProtocolRefs; - if (Tok.is(tok::semi)) { // forward declaration of one protocol. - ConsumeToken(); - ProtocolRefs.push_back(protocolName); - } - if (Tok.is(tok::comma)) { // list of forward declarations. - // Parse the list of forward declarations. - ProtocolRefs.push_back(protocolName); - - while (1) { - ConsumeToken(); // the ',' - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::semi); - return 0; - } - ProtocolRefs.push_back(Tok.getIdentifierInfo()); - ConsumeToken(); // the identifier - - if (Tok.isNot(tok::comma)) - break; - } - // Consume the ';'. - if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) - return 0; - } - if (ProtocolRefs.size() > 0) - return Actions.ActOnForwardProtocolDeclaration(AtLoc, - &ProtocolRefs[0], - ProtocolRefs.size()); - // Last, and definitely not least, parse a protocol declaration. - SourceLocation endProtoLoc; - if (Tok.is(tok::less)) { - if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc)) - return 0; - } - - DeclTy *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, - protocolName, nameLoc, - &ProtocolRefs[0], - ProtocolRefs.size(), endProtoLoc); - ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); - - // The @ sign was already consumed by ParseObjCInterfaceDeclList(). - if (Tok.isObjCAtKeyword(tok::objc_end)) { - ConsumeToken(); // the "end" identifier - return ProtoType; - } - Diag(Tok, diag::err_objc_missing_end); - return 0; -} - -/// objc-implementation: -/// objc-class-implementation-prologue -/// objc-category-implementation-prologue -/// -/// objc-class-implementation-prologue: -/// @implementation identifier objc-superclass[opt] -/// objc-class-instance-variables[opt] -/// -/// objc-category-implementation-prologue: -/// @implementation identifier ( identifier ) - -Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration( - SourceLocation atLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_implementation) && - "ParseObjCAtImplementationDeclaration(): Expected @implementation"); - ConsumeToken(); // the "implementation" identifier - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing class or category name. - return 0; - } - // We have a class or category name - consume it. - IdentifierInfo *nameId = Tok.getIdentifierInfo(); - SourceLocation nameLoc = ConsumeToken(); // consume class or category name - - if (Tok.is(tok::l_paren)) { - // we have a category implementation. - SourceLocation lparenLoc = ConsumeParen(); - SourceLocation categoryLoc, rparenLoc; - IdentifierInfo *categoryId = 0; - - if (Tok.is(tok::identifier)) { - categoryId = Tok.getIdentifierInfo(); - categoryLoc = ConsumeToken(); - } else { - Diag(Tok, diag::err_expected_ident); // missing category name. - return 0; - } - if (Tok.isNot(tok::r_paren)) { - Diag(Tok, diag::err_expected_rparen); - SkipUntil(tok::r_paren, false); // don't stop at ';' - return 0; - } - rparenLoc = ConsumeParen(); - DeclTy *ImplCatType = Actions.ActOnStartCategoryImplementation( - atLoc, nameId, nameLoc, categoryId, - categoryLoc); - ObjCImpDecl = ImplCatType; - return 0; - } - // We have a class implementation - SourceLocation superClassLoc; - IdentifierInfo *superClassId = 0; - if (Tok.is(tok::colon)) { - // We have a super class - ConsumeToken(); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); // missing super class name. - return 0; - } - superClassId = Tok.getIdentifierInfo(); - superClassLoc = ConsumeToken(); // Consume super class name - } - DeclTy *ImplClsType = Actions.ActOnStartClassImplementation( - atLoc, nameId, nameLoc, - superClassId, superClassLoc); - - if (Tok.is(tok::l_brace)) // we have ivars - ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); - ObjCImpDecl = ImplClsType; - - return 0; -} - -Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_end) && - "ParseObjCAtEndDeclaration(): Expected @end"); - ConsumeToken(); // the "end" identifier - if (ObjCImpDecl) - Actions.ActOnAtEnd(atLoc, ObjCImpDecl); - else - Diag(atLoc, diag::warn_expected_implementation); // missing @implementation - return ObjCImpDecl; -} - -/// compatibility-alias-decl: -/// @compatibility_alias alias-name class-name ';' -/// -Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) && - "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias"); - ConsumeToken(); // consume compatibility_alias - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return 0; - } - IdentifierInfo *aliasId = Tok.getIdentifierInfo(); - SourceLocation aliasLoc = ConsumeToken(); // consume alias-name - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return 0; - } - IdentifierInfo *classId = Tok.getIdentifierInfo(); - SourceLocation classLoc = ConsumeToken(); // consume class-name; - if (Tok.isNot(tok::semi)) { - Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias"); - return 0; - } - DeclTy *ClsType = Actions.ActOnCompatiblityAlias(atLoc, - aliasId, aliasLoc, - classId, classLoc); - return ClsType; -} - -/// property-synthesis: -/// @synthesize property-ivar-list ';' -/// -/// property-ivar-list: -/// property-ivar -/// property-ivar-list ',' property-ivar -/// -/// property-ivar: -/// identifier -/// identifier '=' identifier -/// -Parser::DeclTy *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && - "ParseObjCPropertyDynamic(): Expected '@synthesize'"); - SourceLocation loc = ConsumeToken(); // consume dynamic - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return 0; - } - while (Tok.is(tok::identifier)) { - ConsumeToken(); // consume property name - if (Tok.is(tok::equal)) { - // property '=' ivar-name - ConsumeToken(); // consume '=' - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - break; - } - ConsumeToken(); // consume ivar-name - } - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // consume ',' - } - if (Tok.isNot(tok::semi)) - Diag(Tok, diag::err_expected_semi_after, "@synthesize"); - return 0; -} - -/// property-dynamic: -/// @dynamic property-list -/// -/// property-list: -/// identifier -/// property-list ',' identifier -/// -Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && - "ParseObjCPropertyDynamic(): Expected '@dynamic'"); - SourceLocation loc = ConsumeToken(); // consume dynamic - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return 0; - } - while (Tok.is(tok::identifier)) { - ConsumeToken(); // consume property name - if (Tok.isNot(tok::comma)) - break; - ConsumeToken(); // consume ',' - } - if (Tok.isNot(tok::semi)) - Diag(Tok, diag::err_expected_semi_after, "@dynamic"); - return 0; -} - -/// objc-throw-statement: -/// throw expression[opt]; -/// -Parser::StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { - ExprResult Res; - ConsumeToken(); // consume throw - if (Tok.isNot(tok::semi)) { - Res = ParseExpression(); - if (Res.isInvalid) { - SkipUntil(tok::semi); - return true; - } - } - ConsumeToken(); // consume ';' - return Actions.ActOnObjCAtThrowStmt(atLoc, Res.Val); -} - -/// objc-synchronized-statement: -/// @synchronized '(' expression ')' compound-statement -/// -Parser::StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { - ConsumeToken(); // consume synchronized - if (Tok.isNot(tok::l_paren)) { - Diag (Tok, diag::err_expected_lparen_after, "@synchronized"); - return true; - } - ConsumeParen(); // '(' - ExprResult Res = ParseExpression(); - if (Res.isInvalid) { - SkipUntil(tok::semi); - return true; - } - if (Tok.isNot(tok::r_paren)) { - Diag (Tok, diag::err_expected_lbrace); - return true; - } - ConsumeParen(); // ')' - if (Tok.isNot(tok::l_brace)) { - Diag (Tok, diag::err_expected_lbrace); - return true; - } - StmtResult SynchBody = ParseCompoundStatementBody(); - if (SynchBody.isInvalid) - SynchBody = Actions.ActOnNullStmt(Tok.getLocation()); - return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.Val, SynchBody.Val); -} - -/// objc-try-catch-statement: -/// @try compound-statement objc-catch-list[opt] -/// @try compound-statement objc-catch-list[opt] @finally compound-statement -/// -/// objc-catch-list: -/// @catch ( parameter-declaration ) compound-statement -/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement -/// catch-parameter-declaration: -/// parameter-declaration -/// '...' [OBJC2] -/// -Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { - bool catch_or_finally_seen = false; - - ConsumeToken(); // consume try - if (Tok.isNot(tok::l_brace)) { - Diag (Tok, diag::err_expected_lbrace); - return true; - } - StmtResult CatchStmts; - StmtResult FinallyStmt; - StmtResult TryBody = ParseCompoundStatementBody(); - if (TryBody.isInvalid) - TryBody = Actions.ActOnNullStmt(Tok.getLocation()); - - while (Tok.is(tok::at)) { - // At this point, we need to lookahead to determine if this @ is the start - // of an @catch or @finally. We don't want to consume the @ token if this - // is an @try or @encode or something else. - Token AfterAt = GetLookAheadToken(1); - if (!AfterAt.isObjCAtKeyword(tok::objc_catch) && - !AfterAt.isObjCAtKeyword(tok::objc_finally)) - break; - - SourceLocation AtCatchFinallyLoc = ConsumeToken(); - if (Tok.isObjCAtKeyword(tok::objc_catch)) { - StmtTy *FirstPart = 0; - ConsumeToken(); // consume catch - if (Tok.is(tok::l_paren)) { - ConsumeParen(); - EnterScope(Scope::DeclScope); - if (Tok.isNot(tok::ellipsis)) { - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - // FIXME: Is BlockContext right? - Declarator DeclaratorInfo(DS, Declarator::BlockContext); - ParseDeclarator(DeclaratorInfo); - DeclTy *aBlockVarDecl = Actions.ActOnDeclarator(CurScope, - DeclaratorInfo, 0); - StmtResult stmtResult = - Actions.ActOnDeclStmt(aBlockVarDecl, DS.getSourceRange().getBegin(), - DeclaratorInfo.getSourceRange().getEnd()); - FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val; - } else - ConsumeToken(); // consume '...' - SourceLocation RParenLoc = ConsumeParen(); - - StmtResult CatchBody(true); - if (Tok.is(tok::l_brace)) - CatchBody = ParseCompoundStatementBody(); - else - Diag(Tok, diag::err_expected_lbrace); - if (CatchBody.isInvalid) - CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); - CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, RParenLoc, - FirstPart, CatchBody.Val, CatchStmts.Val); - ExitScope(); - } else { - Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after, - "@catch clause"); - return true; - } - catch_or_finally_seen = true; - } else { - assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?"); - ConsumeToken(); // consume finally - - StmtResult FinallyBody(true); - if (Tok.is(tok::l_brace)) - FinallyBody = ParseCompoundStatementBody(); - else - Diag(Tok, diag::err_expected_lbrace); - if (FinallyBody.isInvalid) - FinallyBody = Actions.ActOnNullStmt(Tok.getLocation()); - FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc, - FinallyBody.Val); - catch_or_finally_seen = true; - break; - } - } - if (!catch_or_finally_seen) { - Diag(atLoc, diag::err_missing_catch_finally); - return true; - } - return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.Val, CatchStmts.Val, - FinallyStmt.Val); -} - -/// objc-method-def: objc-method-proto ';'[opt] '{' body '}' -/// -Parser::DeclTy *Parser::ParseObjCMethodDefinition() { - DeclTy *MDecl = ParseObjCMethodPrototype(ObjCImpDecl); - // parse optional ';' - if (Tok.is(tok::semi)) - ConsumeToken(); - - // We should have an opening brace now. - if (Tok.isNot(tok::l_brace)) { - Diag(Tok, diag::err_expected_method_body); - - // Skip over garbage, until we get to '{'. Don't eat the '{'. - SkipUntil(tok::l_brace, true, true); - - // If we didn't find the '{', bail out. - if (Tok.isNot(tok::l_brace)) - return 0; - } - SourceLocation BraceLoc = Tok.getLocation(); - - // Enter a scope for the method body. - EnterScope(Scope::FnScope|Scope::DeclScope); - - // Tell the actions module that we have entered a method definition with the - // specified Declarator for the method. - Actions.ObjCActOnStartOfMethodDef(CurScope, MDecl); - - StmtResult FnBody = ParseCompoundStatementBody(); - - // If the function body could not be parsed, make a bogus compoundstmt. - if (FnBody.isInvalid) - FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, 0, 0, false); - - // Leave the function body scope. - ExitScope(); - - // TODO: Pass argument information. - Actions.ActOnFinishFunctionBody(MDecl, FnBody.Val); - return MDecl; -} - -Parser::StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { - if (Tok.isObjCAtKeyword(tok::objc_try)) { - return ParseObjCTryStmt(AtLoc); - } else if (Tok.isObjCAtKeyword(tok::objc_throw)) - return ParseObjCThrowStmt(AtLoc); - else if (Tok.isObjCAtKeyword(tok::objc_synchronized)) - return ParseObjCSynchronizedStmt(AtLoc); - ExprResult Res = ParseExpressionWithLeadingAt(AtLoc); - if (Res.isInvalid) { - // If the expression is invalid, skip ahead to the next semicolon. Not - // doing this opens us up to the possibility of infinite loops if - // ParseExpression does not consume any tokens. - SkipUntil(tok::semi); - return true; - } - // Otherwise, eat the semicolon. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Res.Val); -} - -Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { - - switch (Tok.getKind()) { - case tok::string_literal: // primary-expression: string-literal - case tok::wide_string_literal: - return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); - default: - break; - } - - switch (Tok.getIdentifierInfo()->getObjCKeywordID()) { - case tok::objc_encode: - return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc)); - case tok::objc_protocol: - return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc)); - case tok::objc_selector: - return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc)); - default: - Diag(AtLoc, diag::err_unexpected_at); - SkipUntil(tok::semi); - return true; - } -} - -/// objc-message-expr: -/// '[' objc-receiver objc-message-args ']' -/// -/// objc-receiver: -/// expression -/// class-name -/// type-name -Parser::ExprResult Parser::ParseObjCMessageExpression() { - assert(Tok.is(tok::l_square) && "'[' expected"); - SourceLocation LBracLoc = ConsumeBracket(); // consume '[' - - // Parse receiver - if (isTokObjCMessageIdentifierReceiver()) { - IdentifierInfo *ReceiverName = Tok.getIdentifierInfo(); - ConsumeToken(); - return ParseObjCMessageExpressionBody(LBracLoc, ReceiverName, 0); - } - - ExprResult Res = ParseAssignmentExpression(); - if (Res.isInvalid) { - Diag(Tok, diag::err_invalid_receiver_to_message); - SkipUntil(tok::r_square); - return Res; - } - return ParseObjCMessageExpressionBody(LBracLoc, 0, Res.Val); -} - -/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse -/// the rest of a message expression. -/// -/// objc-message-args: -/// objc-selector -/// objc-keywordarg-list -/// -/// objc-keywordarg-list: -/// objc-keywordarg -/// objc-keywordarg-list objc-keywordarg -/// -/// objc-keywordarg: -/// selector-name[opt] ':' objc-keywordexpr -/// -/// objc-keywordexpr: -/// nonempty-expr-list -/// -/// nonempty-expr-list: -/// assignment-expression -/// nonempty-expr-list , assignment-expression -/// -Parser::ExprResult -Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, - IdentifierInfo *ReceiverName, - ExprTy *ReceiverExpr) { - // Parse objc-selector - SourceLocation Loc; - IdentifierInfo *selIdent = ParseObjCSelector(Loc); - - llvm::SmallVector KeyIdents; - llvm::SmallVector KeyExprs; - - if (Tok.is(tok::colon)) { - while (1) { - // Each iteration parses a single keyword argument. - KeyIdents.push_back(selIdent); - - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon); - SkipUntil(tok::semi); - return true; - } - ConsumeToken(); // Eat the ':'. - /// Parse the expression after ':' - ExprResult Res = ParseAssignmentExpression(); - if (Res.isInvalid) { - SkipUntil(tok::identifier); - return Res; - } - // We have a valid expression. - KeyExprs.push_back(Res.Val); - - // Check for another keyword selector. - selIdent = ParseObjCSelector(Loc); - if (!selIdent && Tok.isNot(tok::colon)) - break; - // We have a selector or a colon, continue parsing. - } - // Parse the, optional, argument list, comma separated. - while (Tok.is(tok::comma)) { - ConsumeToken(); // Eat the ','. - /// Parse the expression after ',' - ExprResult Res = ParseAssignmentExpression(); - if (Res.isInvalid) { - SkipUntil(tok::identifier); - return Res; - } - // We have a valid expression. - KeyExprs.push_back(Res.Val); - } - } else if (!selIdent) { - Diag(Tok, diag::err_expected_ident); // missing selector name. - SkipUntil(tok::semi); - return true; - } - - if (Tok.isNot(tok::r_square)) { - Diag(Tok, diag::err_expected_rsquare); - SkipUntil(tok::semi); - return true; - } - SourceLocation RBracLoc = ConsumeBracket(); // consume ']' - - unsigned nKeys = KeyIdents.size(); - if (nKeys == 0) - KeyIdents.push_back(selIdent); - Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); - - // We've just parsed a keyword message. - if (ReceiverName) - return Actions.ActOnClassMessage(CurScope, - ReceiverName, Sel, LBracLoc, RBracLoc, - &KeyExprs[0], KeyExprs.size()); - return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracLoc, RBracLoc, - &KeyExprs[0], KeyExprs.size()); -} - -Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { - ExprResult Res = ParseStringLiteralExpression(); - if (Res.isInvalid) return Res; - - // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string - // expressions. At this point, we know that the only valid thing that starts - // with '@' is an @"". - llvm::SmallVector AtLocs; - llvm::SmallVector AtStrings; - AtLocs.push_back(AtLoc); - AtStrings.push_back(Res.Val); - - while (Tok.is(tok::at)) { - AtLocs.push_back(ConsumeToken()); // eat the @. - - ExprResult Res(true); // Invalid unless there is a string literal. - if (isTokenStringLiteral()) - Res = ParseStringLiteralExpression(); - else - Diag(Tok, diag::err_objc_concat_string); - - if (Res.isInvalid) { - while (!AtStrings.empty()) { - Actions.DeleteExpr(AtStrings.back()); - AtStrings.pop_back(); - } - return Res; - } - - AtStrings.push_back(Res.Val); - } - - return Actions.ParseObjCStringLiteral(&AtLocs[0], &AtStrings[0], - AtStrings.size()); -} - -/// objc-encode-expression: -/// @encode ( type-name ) -Parser::ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { - assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!"); - - SourceLocation EncLoc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "@encode"); - return true; - } - - SourceLocation LParenLoc = ConsumeParen(); - - TypeTy *Ty = ParseTypeName(); - - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - - return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, Ty, - RParenLoc); -} - -/// objc-protocol-expression -/// @protocol ( protocol-name ) - -Parser::ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) -{ - SourceLocation ProtoLoc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "@protocol"); - return true; - } - - SourceLocation LParenLoc = ConsumeParen(); - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return true; - } - IdentifierInfo *protocolId = Tok.getIdentifierInfo(); - ConsumeToken(); - - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - - return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, - LParenLoc, RParenLoc); -} - -/// objc-selector-expression -/// @selector '(' objc-keyword-selector ')' -Parser::ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) -{ - SourceLocation SelectorLoc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "@selector"); - return 0; - } - - llvm::SmallVector KeyIdents; - SourceLocation LParenLoc = ConsumeParen(); - SourceLocation sLoc; - IdentifierInfo *SelIdent = ParseObjCSelector(sLoc); - if (!SelIdent && Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_ident); // missing selector name. - return 0; - } - KeyIdents.push_back(SelIdent); - unsigned nColons = 0; - if (Tok.isNot(tok::r_paren)) { - while (1) { - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon); - break; - } - nColons++; - ConsumeToken(); // Eat the ':'. - if (Tok.is(tok::r_paren)) - break; - // Check for another keyword selector. - SourceLocation Loc; - SelIdent = ParseObjCSelector(Loc); - KeyIdents.push_back(SelIdent); - if (!SelIdent && Tok.isNot(tok::colon)) - break; - } - } - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]); - return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc, LParenLoc, - RParenLoc); - } diff --git a/clang/Parse/ParseStmt.cpp b/clang/Parse/ParseStmt.cpp deleted file mode 100644 index f9800219ed5..00000000000 --- a/clang/Parse/ParseStmt.cpp +++ /dev/null @@ -1,1159 +0,0 @@ -//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Statement and Block portions of the Parser -// interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// C99 6.8: Statements and Blocks. -//===----------------------------------------------------------------------===// - -/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. -/// StatementOrDeclaration: -/// statement -/// declaration -/// -/// statement: -/// labeled-statement -/// compound-statement -/// expression-statement -/// selection-statement -/// iteration-statement -/// jump-statement -/// [OBC] objc-throw-statement -/// [OBC] objc-try-catch-statement -/// [OBC] objc-synchronized-statement -/// [GNU] asm-statement -/// [OMP] openmp-construct [TODO] -/// -/// labeled-statement: -/// identifier ':' statement -/// 'case' constant-expression ':' statement -/// 'default' ':' statement -/// -/// selection-statement: -/// if-statement -/// switch-statement -/// -/// iteration-statement: -/// while-statement -/// do-statement -/// for-statement -/// -/// expression-statement: -/// expression[opt] ';' -/// -/// jump-statement: -/// 'goto' identifier ';' -/// 'continue' ';' -/// 'break' ';' -/// 'return' expression[opt] ';' -/// [GNU] 'goto' '*' expression ';' -/// -/// [OBC] objc-throw-statement: -/// [OBC] '@' 'throw' expression ';' -/// [OBC] '@' 'throw' ';' -/// -Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { - const char *SemiError = 0; - Parser::StmtResult Res; - - // Cases in this switch statement should fall through if the parser expects - // the token to end in a semicolon (in which case SemiError should be set), - // or they directly 'return;' if not. - tok::TokenKind Kind = Tok.getKind(); - SourceLocation AtLoc; - switch (Kind) { - case tok::identifier: // C99 6.8.1: labeled-statement - // identifier ':' statement - // declaration (if !OnlyStatement) - // expression[opt] ';' - return ParseIdentifierStatement(OnlyStatement); - - case tok::at: // May be a @try or @throw statement - { - AtLoc = ConsumeToken(); // consume @ - return ParseObjCAtStatement(AtLoc); - } - - default: - if (!OnlyStatement && isDeclarationSpecifier()) { - SourceLocation DeclStart = Tok.getLocation(); - DeclTy *Res = ParseDeclaration(Declarator::BlockContext); - // FIXME: Pass in the right location for the end of the declstmt. - return Actions.ActOnDeclStmt(Res, DeclStart, DeclStart); - } else if (Tok.is(tok::r_brace)) { - Diag(Tok, diag::err_expected_statement); - return true; - } else { - // expression[opt] ';' - ExprResult Res = ParseExpression(); - if (Res.isInvalid) { - // If the expression is invalid, skip ahead to the next semicolon. Not - // doing this opens us up to the possibility of infinite loops if - // ParseExpression does not consume any tokens. - SkipUntil(tok::semi); - return true; - } - // Otherwise, eat the semicolon. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Res.Val); - } - - case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(); - case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(); - - case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(); - case tok::semi: // C99 6.8.3p3: expression[opt] ';' - return Actions.ActOnNullStmt(ConsumeToken()); - - case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(); - case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(); - - case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(); - case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(); - SemiError = "do/while loop"; - break; - case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(); - - case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(); - SemiError = "goto statement"; - break; - case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(); - SemiError = "continue statement"; - break; - case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(); - SemiError = "break statement"; - break; - case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(); - SemiError = "return statement"; - break; - - case tok::kw_asm: - bool msAsm = false; - Res = ParseAsmStatement(msAsm); - if (msAsm) return Res; - SemiError = "asm statement"; - break; - } - - // If we reached this code, the statement must end in a semicolon. - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else { - Diag(Tok, diag::err_expected_semi_after, SemiError); - SkipUntil(tok::semi); - } - return Res; -} - -/// ParseIdentifierStatement - Because we don't have two-token lookahead, we -/// have a bit of a quandry here. Reading the identifier is necessary to see if -/// there is a ':' after it. If there is, this is a label, regardless of what -/// else the identifier can mean. If not, this is either part of a declaration -/// (if the identifier is a type-name) or part of an expression. -/// -/// labeled-statement: -/// identifier ':' statement -/// [GNU] identifier ':' attributes[opt] statement -/// declaration (if !OnlyStatement) -/// expression[opt] ';' -/// -Parser::StmtResult Parser::ParseIdentifierStatement(bool OnlyStatement) { - assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && - "Not an identifier!"); - - Token IdentTok = Tok; // Save the whole token. - ConsumeToken(); // eat the identifier. - - // identifier ':' statement - if (Tok.is(tok::colon)) { - SourceLocation ColonLoc = ConsumeToken(); - - // Read label attributes, if present. - DeclTy *AttrList = 0; - if (Tok.is(tok::kw___attribute)) - // TODO: save these somewhere. - AttrList = ParseAttributes(); - - StmtResult SubStmt = ParseStatement(); - - // Broken substmt shouldn't prevent the label from being added to the AST. - if (SubStmt.isInvalid) - SubStmt = Actions.ActOnNullStmt(ColonLoc); - - return Actions.ActOnLabelStmt(IdentTok.getLocation(), - IdentTok.getIdentifierInfo(), - ColonLoc, SubStmt.Val); - } - - // Check to see if this is a declaration. - void *TypeRep; - if (!OnlyStatement && - (TypeRep = Actions.isTypeName(*IdentTok.getIdentifierInfo(), CurScope))) { - // Handle this. Warn/disable if in middle of block and !C99. - DeclSpec DS; - - // Add the typedef name to the start of the decl-specs. - const char *PrevSpec = 0; - int isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, - IdentTok.getLocation(), PrevSpec, - TypeRep); - assert(!isInvalid && "First declspec can't be invalid!"); - SourceLocation endProtoLoc; - if (Tok.is(tok::less)) { - llvm::SmallVector ProtocolRefs; - ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc); - llvm::SmallVector *ProtocolDecl = - new llvm::SmallVector; - DS.setProtocolQualifiers(ProtocolDecl); - Actions.FindProtocolDeclaration(IdentTok.getLocation(), - &ProtocolRefs[0], ProtocolRefs.size(), - *ProtocolDecl); - } - - // ParseDeclarationSpecifiers will continue from there. - ParseDeclarationSpecifiers(DS); - - // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" - // declaration-specifiers init-declarator-list[opt] ';' - if (Tok.is(tok::semi)) { - // TODO: emit error on 'int;' or 'const enum foo;'. - // if (!DS.isMissingDeclaratorOk()) Diag(...); - - ConsumeToken(); - // FIXME: Return this as a type decl. - return 0; - } - - // Parse all the declarators. - Declarator DeclaratorInfo(DS, Declarator::BlockContext); - ParseDeclarator(DeclaratorInfo); - - DeclTy *Decl = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); - if (!Decl) return 0; - return Actions.ActOnDeclStmt(Decl, DS.getSourceRange().getBegin(), - DeclaratorInfo.getSourceRange().getEnd()); - } - - // Otherwise, this is an expression. Seed it with II and parse it. - ExprResult Res = ParseExpressionWithLeadingIdentifier(IdentTok); - if (Res.isInvalid) { - SkipUntil(tok::semi); - return true; - } else if (Tok.isNot(tok::semi)) { - Diag(Tok, diag::err_expected_semi_after, "expression"); - SkipUntil(tok::semi); - return true; - } else { - ConsumeToken(); - // Convert expr to a stmt. - return Actions.ActOnExprStmt(Res.Val); - } -} - -/// ParseCaseStatement -/// labeled-statement: -/// 'case' constant-expression ':' statement -/// [GNU] 'case' constant-expression '...' constant-expression ':' statement -/// -/// Note that this does not parse the 'statement' at the end. -/// -Parser::StmtResult Parser::ParseCaseStatement() { - assert(Tok.is(tok::kw_case) && "Not a case stmt!"); - SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'. - - ExprResult LHS = ParseConstantExpression(); - if (LHS.isInvalid) { - SkipUntil(tok::colon); - return true; - } - - // GNU case range extension. - SourceLocation DotDotDotLoc; - ExprTy *RHSVal = 0; - if (Tok.is(tok::ellipsis)) { - Diag(Tok, diag::ext_gnu_case_range); - DotDotDotLoc = ConsumeToken(); - - ExprResult RHS = ParseConstantExpression(); - if (RHS.isInvalid) { - SkipUntil(tok::colon); - return true; - } - RHSVal = RHS.Val; - } - - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon_after, "'case'"); - SkipUntil(tok::colon); - return true; - } - - SourceLocation ColonLoc = ConsumeToken(); - - // Diagnose the common error "switch (X) { case 4: }", which is not valid. - if (Tok.is(tok::r_brace)) { - Diag(Tok, diag::err_label_end_of_compound_statement); - return true; - } - - StmtResult SubStmt = ParseStatement(); - - // Broken substmt shouldn't prevent the case from being added to the AST. - if (SubStmt.isInvalid) - SubStmt = Actions.ActOnNullStmt(ColonLoc); - - return Actions.ActOnCaseStmt(CaseLoc, LHS.Val, DotDotDotLoc, RHSVal, ColonLoc, - SubStmt.Val); -} - -/// ParseDefaultStatement -/// labeled-statement: -/// 'default' ':' statement -/// Note that this does not parse the 'statement' at the end. -/// -Parser::StmtResult Parser::ParseDefaultStatement() { - assert(Tok.is(tok::kw_default) && "Not a default stmt!"); - SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. - - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon_after, "'default'"); - SkipUntil(tok::colon); - return true; - } - - SourceLocation ColonLoc = ConsumeToken(); - - // Diagnose the common error "switch (X) {... default: }", which is not valid. - if (Tok.is(tok::r_brace)) { - Diag(Tok, diag::err_label_end_of_compound_statement); - return true; - } - - StmtResult SubStmt = ParseStatement(); - if (SubStmt.isInvalid) - return true; - - return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val, CurScope); -} - - -/// ParseCompoundStatement - Parse a "{}" block. -/// -/// compound-statement: [C99 6.8.2] -/// { block-item-list[opt] } -/// [GNU] { label-declarations block-item-list } [TODO] -/// -/// block-item-list: -/// block-item -/// block-item-list block-item -/// -/// block-item: -/// declaration -/// [GNU] '__extension__' declaration -/// statement -/// [OMP] openmp-directive [TODO] -/// -/// [GNU] label-declarations: -/// [GNU] label-declaration -/// [GNU] label-declarations label-declaration -/// -/// [GNU] label-declaration: -/// [GNU] '__label__' identifier-list ';' -/// -/// [OMP] openmp-directive: [TODO] -/// [OMP] barrier-directive -/// [OMP] flush-directive -/// -Parser::StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { - assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); - - // Enter a scope to hold everything within the compound stmt. Compound - // statements can always hold declarations. - EnterScope(Scope::DeclScope); - - // Parse the statements in the body. - StmtResult Body = ParseCompoundStatementBody(isStmtExpr); - - ExitScope(); - return Body; -} - - -/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the -/// ActOnCompoundStmt action. This expects the '{' to be the current token, and -/// consume the '}' at the end of the block. It does not manipulate the scope -/// stack. -Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { - SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'. - - // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are - // only allowed at the start of a compound stmt regardless of the language. - - llvm::SmallVector Stmts; - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - StmtResult R; - if (Tok.isNot(tok::kw___extension__)) { - R = ParseStatementOrDeclaration(false); - } else { - // __extension__ can start declarations and it can also be a unary - // operator for expressions. Consume multiple __extension__ markers here - // until we can determine which is which. - SourceLocation ExtLoc = ConsumeToken(); - while (Tok.is(tok::kw___extension__)) - ConsumeToken(); - - // __extension__ silences extension warnings in the subexpression. - bool SavedExtWarn = Diags.getWarnOnExtensions(); - Diags.setWarnOnExtensions(false); - - // If this is the start of a declaration, parse it as such. - if (isDeclarationSpecifier()) { - // FIXME: Save the __extension__ on the decl as a node somehow. - SourceLocation DeclStart = Tok.getLocation(); - DeclTy *Res = ParseDeclaration(Declarator::BlockContext); - // FIXME: Pass in the right location for the end of the declstmt. - R = Actions.ActOnDeclStmt(Res, DeclStart, DeclStart); - - Diags.setWarnOnExtensions(SavedExtWarn); - } else { - // Otherwise this was a unary __extension__ marker. Parse the - // subexpression and add the __extension__ unary op. - ExprResult Res = ParseCastExpression(false); - Diags.setWarnOnExtensions(SavedExtWarn); - - if (Res.isInvalid) { - SkipUntil(tok::semi); - continue; - } - - // Add the __extension__ node to the AST. - Res = Actions.ActOnUnaryOp(ExtLoc, tok::kw___extension__, Res.Val); - if (Res.isInvalid) - continue; - - // Eat the semicolon at the end of stmt and convert the expr into a stmt. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - R = Actions.ActOnExprStmt(Res.Val); - } - } - - if (!R.isInvalid && R.Val) - Stmts.push_back(R.Val); - } - - // We broke out of the while loop because we found a '}' or EOF. - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return true; - } - - SourceLocation RBraceLoc = ConsumeBrace(); - return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, - &Stmts[0], Stmts.size(), isStmtExpr); -} - -/// ParseIfStatement -/// if-statement: [C99 6.8.4.1] -/// 'if' '(' expression ')' statement -/// 'if' '(' expression ')' statement 'else' statement -/// -Parser::StmtResult Parser::ParseIfStatement() { - assert(Tok.is(tok::kw_if) && "Not an if stmt!"); - SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "if"); - SkipUntil(tok::semi); - return true; - } - - // C99 6.8.4p3 - In C99, the if statement is a block. This is not - // the case for C90. - if (getLang().C99) - EnterScope(Scope::DeclScope); - - // Parse the condition. - ExprResult CondExp = ParseSimpleParenExpression(); - if (CondExp.isInvalid) { - SkipUntil(tok::semi); - if (getLang().C99) - ExitScope(); - return true; - } - - // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if - // there is no compound stmt. C90 does not have this clause. We only do this - // if the body isn't a compound statement to avoid push/pop in common cases. - bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); - if (NeedsInnerScope) EnterScope(Scope::DeclScope); - - // Read the 'then' stmt. - SourceLocation ThenStmtLoc = Tok.getLocation(); - StmtResult ThenStmt = ParseStatement(); - - // Pop the 'if' scope if needed. - if (NeedsInnerScope) ExitScope(); - - // If it has an else, parse it. - SourceLocation ElseLoc; - SourceLocation ElseStmtLoc; - StmtResult ElseStmt(false); - - if (Tok.is(tok::kw_else)) { - ElseLoc = ConsumeToken(); - - // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if - // there is no compound stmt. C90 does not have this clause. We only do - // this if the body isn't a compound statement to avoid push/pop in common - // cases. - NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); - if (NeedsInnerScope) EnterScope(Scope::DeclScope); - - ElseStmtLoc = Tok.getLocation(); - ElseStmt = ParseStatement(); - - // Pop the 'else' scope if needed. - if (NeedsInnerScope) ExitScope(); - } - - if (getLang().C99) - ExitScope(); - - // If the then or else stmt is invalid and the other is valid (and present), - // make turn the invalid one into a null stmt to avoid dropping the other - // part. If both are invalid, return error. - if ((ThenStmt.isInvalid && ElseStmt.isInvalid) || - (ThenStmt.isInvalid && ElseStmt.Val == 0) || - (ThenStmt.Val == 0 && ElseStmt.isInvalid)) { - // Both invalid, or one is invalid and other is non-present: delete cond and - // return error. - Actions.DeleteExpr(CondExp.Val); - return true; - } - - // Now if either are invalid, replace with a ';'. - if (ThenStmt.isInvalid) - ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); - if (ElseStmt.isInvalid) - ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - - return Actions.ActOnIfStmt(IfLoc, CondExp.Val, ThenStmt.Val, - ElseLoc, ElseStmt.Val); -} - -/// ParseSwitchStatement -/// switch-statement: -/// 'switch' '(' expression ')' statement -Parser::StmtResult Parser::ParseSwitchStatement() { - assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); - SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "switch"); - SkipUntil(tok::semi); - return true; - } - - // C99 6.8.4p3 - In C99, the switch statement is a block. This is - // not the case for C90. Start the switch scope. - if (getLang().C99) - EnterScope(Scope::BreakScope|Scope::DeclScope); - else - EnterScope(Scope::BreakScope); - - // Parse the condition. - ExprResult Cond = ParseSimpleParenExpression(); - - if (Cond.isInvalid) { - ExitScope(); - return true; - } - - StmtResult Switch = Actions.ActOnStartOfSwitchStmt(Cond.Val); - - // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if - // there is no compound stmt. C90 does not have this clause. We only do this - // if the body isn't a compound statement to avoid push/pop in common cases. - bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); - if (NeedsInnerScope) EnterScope(Scope::DeclScope); - - // Read the body statement. - StmtResult Body = ParseStatement(); - - // Pop the body scope if needed. - if (NeedsInnerScope) ExitScope(); - - if (Body.isInvalid) { - Body = Actions.ActOnNullStmt(Tok.getLocation()); - // FIXME: Remove the case statement list from the Switch statement. - } - - ExitScope(); - - return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.Val, Body.Val); -} - -/// ParseWhileStatement -/// while-statement: [C99 6.8.5.1] -/// 'while' '(' expression ')' statement -Parser::StmtResult Parser::ParseWhileStatement() { - assert(Tok.is(tok::kw_while) && "Not a while stmt!"); - SourceLocation WhileLoc = Tok.getLocation(); - ConsumeToken(); // eat the 'while'. - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "while"); - SkipUntil(tok::semi); - return true; - } - - // C99 6.8.5p5 - In C99, the while statement is a block. This is not - // the case for C90. Start the loop scope. - if (getLang().C99) - EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); - else - EnterScope(Scope::BreakScope | Scope::ContinueScope); - - // Parse the condition. - ExprResult Cond = ParseSimpleParenExpression(); - - // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if - // there is no compound stmt. C90 does not have this clause. We only do this - // if the body isn't a compound statement to avoid push/pop in common cases. - bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); - if (NeedsInnerScope) EnterScope(Scope::DeclScope); - - // Read the body statement. - StmtResult Body = ParseStatement(); - - // Pop the body scope if needed. - if (NeedsInnerScope) ExitScope(); - - ExitScope(); - - if (Cond.isInvalid || Body.isInvalid) return true; - - return Actions.ActOnWhileStmt(WhileLoc, Cond.Val, Body.Val); -} - -/// ParseDoStatement -/// do-statement: [C99 6.8.5.2] -/// 'do' statement 'while' '(' expression ')' ';' -/// Note: this lets the caller parse the end ';'. -Parser::StmtResult Parser::ParseDoStatement() { - assert(Tok.is(tok::kw_do) && "Not a do stmt!"); - SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. - - // C99 6.8.5p5 - In C99, the do statement is a block. This is not - // the case for C90. Start the loop scope. - if (getLang().C99) - EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); - else - EnterScope(Scope::BreakScope | Scope::ContinueScope); - - // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if - // there is no compound stmt. C90 does not have this clause. We only do this - // if the body isn't a compound statement to avoid push/pop in common cases. - bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); - if (NeedsInnerScope) EnterScope(Scope::DeclScope); - - // Read the body statement. - StmtResult Body = ParseStatement(); - - // Pop the body scope if needed. - if (NeedsInnerScope) ExitScope(); - - if (Tok.isNot(tok::kw_while)) { - ExitScope(); - Diag(Tok, diag::err_expected_while); - Diag(DoLoc, diag::err_matching, "do"); - SkipUntil(tok::semi); - return true; - } - SourceLocation WhileLoc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - ExitScope(); - Diag(Tok, diag::err_expected_lparen_after, "do/while"); - SkipUntil(tok::semi); - return true; - } - - // Parse the condition. - ExprResult Cond = ParseSimpleParenExpression(); - - ExitScope(); - - if (Cond.isInvalid || Body.isInvalid) return true; - - return Actions.ActOnDoStmt(DoLoc, Body.Val, WhileLoc, Cond.Val); -} - -/// ParseForStatement -/// for-statement: [C99 6.8.5.3] -/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement -/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement -/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement -/// [OBJC2] 'for' '(' expr 'in' expr ')' statement -Parser::StmtResult Parser::ParseForStatement() { - assert(Tok.is(tok::kw_for) && "Not a for stmt!"); - SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "for"); - SkipUntil(tok::semi); - return true; - } - - // C99 6.8.5p5 - In C99, the for statement is a block. This is not - // the case for C90. Start the loop scope. - if (getLang().C99) - EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); - else - EnterScope(Scope::BreakScope | Scope::ContinueScope); - - SourceLocation LParenLoc = ConsumeParen(); - ExprResult Value; - - StmtTy *FirstPart = 0; - ExprTy *SecondPart = 0; - StmtTy *ThirdPart = 0; - bool ForEach = false; - - // Parse the first part of the for specifier. - if (Tok.is(tok::semi)) { // for (; - // no first part, eat the ';'. - ConsumeToken(); - } else if (isDeclarationSpecifier()) { // for (int X = 4; - // Parse declaration, which eats the ';'. - if (!getLang().C99) // Use of C99-style for loops in C90 mode? - Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); - - SourceLocation DeclStart = Tok.getLocation(); - DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext); - // FIXME: Pass in the right location for the end of the declstmt. - StmtResult stmtResult = Actions.ActOnDeclStmt(aBlockVarDecl, DeclStart, - DeclStart); - FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val; - if ((ForEach = isTokIdentifier_in())) { - ConsumeToken(); // consume 'in' - Value = ParseExpression(); - if (!Value.isInvalid) - SecondPart = Value.Val; - } - } else { - Value = ParseExpression(); - - // Turn the expression into a stmt. - if (!Value.isInvalid) { - StmtResult R = Actions.ActOnExprStmt(Value.Val); - if (!R.isInvalid) - FirstPart = R.Val; - } - - if (Tok.is(tok::semi)) { - ConsumeToken(); - } - else if ((ForEach = isTokIdentifier_in())) { - ConsumeToken(); // consume 'in' - Value = ParseExpression(); - if (!Value.isInvalid) - SecondPart = Value.Val; - } - else { - if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for); - SkipUntil(tok::semi); - } - } - if (!ForEach) { - // Parse the second part of the for specifier. - if (Tok.is(tok::semi)) { // for (...;; - // no second part. - Value = ExprResult(); - } else { - Value = ParseExpression(); - if (!Value.isInvalid) - SecondPart = Value.Val; - } - - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else { - if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for); - SkipUntil(tok::semi); - } - - // Parse the third part of the for specifier. - if (Tok.is(tok::r_paren)) { // for (...;...;) - // no third part. - Value = ExprResult(); - } else { - Value = ParseExpression(); - if (!Value.isInvalid) { - // Turn the expression into a stmt. - StmtResult R = Actions.ActOnExprStmt(Value.Val); - if (!R.isInvalid) - ThirdPart = R.Val; - } - } - } - // Match the ')'. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - - // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if - // there is no compound stmt. C90 does not have this clause. We only do this - // if the body isn't a compound statement to avoid push/pop in common cases. - bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); - if (NeedsInnerScope) EnterScope(Scope::DeclScope); - - // Read the body statement. - StmtResult Body = ParseStatement(); - - // Pop the body scope if needed. - if (NeedsInnerScope) ExitScope(); - - // Leave the for-scope. - ExitScope(); - - if (Body.isInvalid) - return Body; - - if (!ForEach) - return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart, - SecondPart, ThirdPart, RParenLoc, Body.Val); - else - return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart, - SecondPart, RParenLoc, Body.Val); -} - -/// ParseGotoStatement -/// jump-statement: -/// 'goto' identifier ';' -/// [GNU] 'goto' '*' expression ';' -/// -/// Note: this lets the caller parse the end ';'. -/// -Parser::StmtResult Parser::ParseGotoStatement() { - assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); - SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. - - StmtResult Res; - if (Tok.is(tok::identifier)) { - Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), - Tok.getIdentifierInfo()); - ConsumeToken(); - } else if (Tok.is(tok::star) && !getLang().NoExtensions) { - // GNU indirect goto extension. - Diag(Tok, diag::ext_gnu_indirect_goto); - SourceLocation StarLoc = ConsumeToken(); - ExprResult R = ParseExpression(); - if (R.isInvalid) { // Skip to the semicolon, but don't consume it. - SkipUntil(tok::semi, false, true); - return true; - } - Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.Val); - } else { - Diag(Tok, diag::err_expected_ident); - return true; - } - - return Res; -} - -/// ParseContinueStatement -/// jump-statement: -/// 'continue' ';' -/// -/// Note: this lets the caller parse the end ';'. -/// -Parser::StmtResult Parser::ParseContinueStatement() { - SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. - return Actions.ActOnContinueStmt(ContinueLoc, CurScope); -} - -/// ParseBreakStatement -/// jump-statement: -/// 'break' ';' -/// -/// Note: this lets the caller parse the end ';'. -/// -Parser::StmtResult Parser::ParseBreakStatement() { - SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. - return Actions.ActOnBreakStmt(BreakLoc, CurScope); -} - -/// ParseReturnStatement -/// jump-statement: -/// 'return' expression[opt] ';' -Parser::StmtResult Parser::ParseReturnStatement() { - assert(Tok.is(tok::kw_return) && "Not a return stmt!"); - SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. - - ExprResult R(0); - if (Tok.isNot(tok::semi)) { - R = ParseExpression(); - if (R.isInvalid) { // Skip to the semicolon, but don't consume it. - SkipUntil(tok::semi, false, true); - return true; - } - } - return Actions.ActOnReturnStmt(ReturnLoc, R.Val); -} - -/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this -/// routine is called to skip/ignore tokens that comprise the MS asm statement. -Parser::StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { - if (Tok.is(tok::l_brace)) { - unsigned short savedBraceCount = BraceCount; - do { - ConsumeAnyToken(); - } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); - } else { - // From the MS website: If used without braces, the __asm keyword means - // that the rest of the line is an assembly-language statement. - SourceManager &SrcMgr = PP.getSourceManager(); - SourceLocation TokLoc = Tok.getLocation(); - unsigned lineNo = SrcMgr.getLogicalLineNumber(TokLoc); - do { - ConsumeAnyToken(); - TokLoc = Tok.getLocation(); - } while ((SrcMgr.getLogicalLineNumber(TokLoc) == lineNo) && - Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && - Tok.isNot(tok::eof)); - } - return false; -} - -/// ParseAsmStatement - Parse a GNU extended asm statement. -/// asm-statement: -/// gnu-asm-statement -/// ms-asm-statement -/// -/// [GNU] gnu-asm-statement: -/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' -/// -/// [GNU] asm-argument: -/// asm-string-literal -/// asm-string-literal ':' asm-operands[opt] -/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] -/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] -/// ':' asm-clobbers -/// -/// [GNU] asm-clobbers: -/// asm-string-literal -/// asm-clobbers ',' asm-string-literal -/// -/// [MS] ms-asm-statement: -/// '__asm' assembly-instruction ';'[opt] -/// '__asm' '{' assembly-instruction-list '}' ';'[opt] -/// -/// [MS] assembly-instruction-list: -/// assembly-instruction ';'[opt] -/// assembly-instruction-list ';' assembly-instruction ';'[opt] -/// -Parser::StmtResult Parser::ParseAsmStatement(bool &msAsm) { - assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); - SourceLocation AsmLoc = ConsumeToken(); - - if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { - msAsm = true; - return FuzzyParseMicrosoftAsmStatement(); - } - DeclSpec DS; - SourceLocation Loc = Tok.getLocation(); - ParseTypeQualifierListOpt(DS); - - // GNU asms accept, but warn, about type-qualifiers other than volatile. - if (DS.getTypeQualifiers() & DeclSpec::TQ_const) - Diag(Loc, diag::w_asm_qualifier_ignored, "const"); - if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) - Diag(Loc, diag::w_asm_qualifier_ignored, "restrict"); - - // Remember if this was a volatile asm. - bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; - bool isSimple = false; - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "asm"); - SkipUntil(tok::r_paren); - return true; - } - Loc = ConsumeParen(); - - ExprResult AsmString = ParseAsmStringLiteral(); - if (AsmString.isInvalid) - return true; - - llvm::SmallVector Names; - llvm::SmallVector Constraints; - llvm::SmallVector Exprs; - llvm::SmallVector Clobbers; - - unsigned NumInputs = 0, NumOutputs = 0; - - SourceLocation RParenLoc; - if (Tok.is(tok::r_paren)) { - // We have a simple asm expression - isSimple = true; - - RParenLoc = ConsumeParen(); - } else { - // Parse Outputs, if present. - if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) - return true; - - NumOutputs = Names.size(); - - // Parse Inputs, if present. - if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) - return true; - - assert(Names.size() == Constraints.size() && - Constraints.size() == Exprs.size() - && "Input operand size mismatch!"); - - NumInputs = Names.size() - NumOutputs; - - // Parse the clobbers, if present. - if (Tok.is(tok::colon)) { - ConsumeToken(); - - // Parse the asm-string list for clobbers. - while (1) { - ExprResult Clobber = ParseAsmStringLiteral(); - - if (Clobber.isInvalid) - break; - - Clobbers.push_back(Clobber.Val); - - if (Tok.isNot(tok::comma)) break; - ConsumeToken(); - } - } - - RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); - } - - return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile, - NumOutputs, NumInputs, - &Names[0], &Constraints[0], &Exprs[0], - AsmString.Val, - Clobbers.size(), &Clobbers[0], - RParenLoc); -} - -/// ParseAsmOperands - Parse the asm-operands production as used by -/// asm-statement. We also parse a leading ':' token. If the leading colon is -/// not present, we do not parse anything. -/// -/// [GNU] asm-operands: -/// asm-operand -/// asm-operands ',' asm-operand -/// -/// [GNU] asm-operand: -/// asm-string-literal '(' expression ')' -/// '[' identifier ']' asm-string-literal '(' expression ')' -/// -bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, - llvm::SmallVectorImpl &Constraints, - llvm::SmallVectorImpl &Exprs) { - // Only do anything if this operand is present. - if (Tok.isNot(tok::colon)) return false; - ConsumeToken(); - - // 'asm-operands' isn't present? - if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) - return false; - - while (1) { - // Read the [id] if present. - if (Tok.is(tok::l_square)) { - SourceLocation Loc = ConsumeBracket(); - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren); - return true; - } - - IdentifierInfo *II = Tok.getIdentifierInfo(); - ConsumeToken(); - - Names.push_back(std::string(II->getName(), II->getLength())); - MatchRHSPunctuation(tok::r_square, Loc); - } else - Names.push_back(std::string()); - - ExprResult Constraint = ParseAsmStringLiteral(); - if (Constraint.isInvalid) { - SkipUntil(tok::r_paren); - return true; - } - Constraints.push_back(Constraint.Val); - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "asm operand"); - SkipUntil(tok::r_paren); - return true; - } - - // Read the parenthesized expression. - ExprResult Res = ParseSimpleParenExpression(); - if (Res.isInvalid) { - SkipUntil(tok::r_paren); - return true; - } - Exprs.push_back(Res.Val); - // Eat the comma and continue parsing if it exists. - if (Tok.isNot(tok::comma)) return false; - ConsumeToken(); - } - - return true; -} - -Parser::DeclTy *Parser::ParseFunctionStatementBody(DeclTy *Decl, - SourceLocation L, SourceLocation R) { - // Do not enter a scope for the brace, as the arguments are in the same scope - // (the function body) as the body itself. Instead, just read the statement - // list and put it into a CompoundStmt for safe keeping. - StmtResult FnBody = ParseCompoundStatementBody(); - - // If the function body could not be parsed, make a bogus compoundstmt. - if (FnBody.isInvalid) - FnBody = Actions.ActOnCompoundStmt(L, R, 0, 0, false); - - // Leave the function body scope. - ExitScope(); - - return Actions.ActOnFinishFunctionBody(Decl, FnBody.Val); -} diff --git a/clang/Parse/Parser.cpp b/clang/Parse/Parser.cpp deleted file mode 100644 index 703144b3c44..00000000000 --- a/clang/Parse/Parser.cpp +++ /dev/null @@ -1,647 +0,0 @@ -//===--- Parser.cpp - C Language Family Parser ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Parser interfaces. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -using namespace clang; - -Parser::Parser(Preprocessor &pp, Action &actions) - : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) { - Tok.setKind(tok::eof); - CurScope = 0; - NumCachedScopes = 0; - ParenCount = BracketCount = BraceCount = 0; - ObjCImpDecl = 0; -} - -/// Out-of-line virtual destructor to provide home for Action class. -Action::~Action() {} - - -void Parser::Diag(SourceLocation Loc, unsigned DiagID, - const std::string &Msg) { - Diags.Report(FullSourceLoc(Loc,PP.getSourceManager()), DiagID, &Msg, 1); -} - -/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), -/// this helper function matches and consumes the specified RHS token if -/// present. If not present, it emits the specified diagnostic indicating -/// that the parser failed to match the RHS of the token at LHSLoc. LHSName -/// should be the name of the unmatched LHS token. -SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, - SourceLocation LHSLoc) { - - if (Tok.is(RHSTok)) - return ConsumeAnyToken(); - - SourceLocation R = Tok.getLocation(); - const char *LHSName = "unknown"; - diag::kind DID = diag::err_parse_error; - switch (RHSTok) { - default: break; - case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; - case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; - case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; - case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; - } - Diag(Tok, DID); - Diag(LHSLoc, diag::err_matching, LHSName); - SkipUntil(RHSTok); - return R; -} - -/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the -/// input. If so, it is consumed and false is returned. -/// -/// If the input is malformed, this emits the specified diagnostic. Next, if -/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is -/// returned. -bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, - const char *Msg, tok::TokenKind SkipToTok) { - if (Tok.is(ExpectedTok)) { - ConsumeAnyToken(); - return false; - } - - Diag(Tok, DiagID, Msg); - if (SkipToTok != tok::unknown) - SkipUntil(SkipToTok); - return true; -} - -//===----------------------------------------------------------------------===// -// Error recovery. -//===----------------------------------------------------------------------===// - -/// SkipUntil - Read tokens until we get to the specified token, then consume -/// it (unless DontConsume is true). Because we cannot guarantee that the -/// token will ever occur, this skips to the next token, or to some likely -/// good stopping point. If StopAtSemi is true, skipping will stop at a ';' -/// character. -/// -/// If SkipUntil finds the specified token, it returns true, otherwise it -/// returns false. -bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, - bool StopAtSemi, bool DontConsume) { - // We always want this function to skip at least one token if the first token - // isn't T and if not at EOF. - bool isFirstTokenSkipped = true; - while (1) { - // If we found one of the tokens, stop and return true. - for (unsigned i = 0; i != NumToks; ++i) { - if (Tok.is(Toks[i])) { - if (DontConsume) { - // Noop, don't consume the token. - } else { - ConsumeAnyToken(); - } - return true; - } - } - - switch (Tok.getKind()) { - case tok::eof: - // Ran out of tokens. - return false; - - case tok::l_paren: - // Recursively skip properly-nested parens. - ConsumeParen(); - SkipUntil(tok::r_paren, false); - break; - case tok::l_square: - // Recursively skip properly-nested square brackets. - ConsumeBracket(); - SkipUntil(tok::r_square, false); - break; - case tok::l_brace: - // Recursively skip properly-nested braces. - ConsumeBrace(); - SkipUntil(tok::r_brace, false); - break; - - // Okay, we found a ']' or '}' or ')', which we think should be balanced. - // Since the user wasn't looking for this token (if they were, it would - // already be handled), this isn't balanced. If there is a LHS token at a - // higher level, we will assume that this matches the unbalanced token - // and return it. Otherwise, this is a spurious RHS token, which we skip. - case tok::r_paren: - if (ParenCount && !isFirstTokenSkipped) - return false; // Matches something. - ConsumeParen(); - break; - case tok::r_square: - if (BracketCount && !isFirstTokenSkipped) - return false; // Matches something. - ConsumeBracket(); - break; - case tok::r_brace: - if (BraceCount && !isFirstTokenSkipped) - return false; // Matches something. - ConsumeBrace(); - break; - - case tok::string_literal: - case tok::wide_string_literal: - ConsumeStringToken(); - break; - case tok::semi: - if (StopAtSemi) - return false; - // FALL THROUGH. - default: - // Skip this token. - ConsumeToken(); - break; - } - isFirstTokenSkipped = false; - } -} - -//===----------------------------------------------------------------------===// -// Scope manipulation -//===----------------------------------------------------------------------===// - -/// EnterScope - Start a new scope. -void Parser::EnterScope(unsigned ScopeFlags) { - if (NumCachedScopes) { - Scope *N = ScopeCache[--NumCachedScopes]; - N->Init(CurScope, ScopeFlags); - CurScope = N; - } else { - CurScope = new Scope(CurScope, ScopeFlags); - } -} - -/// ExitScope - Pop a scope off the scope stack. -void Parser::ExitScope() { - assert(CurScope && "Scope imbalance!"); - - // Inform the actions module that this scope is going away if there are any - // decls in it. - if (!CurScope->decl_empty()) - Actions.ActOnPopScope(Tok.getLocation(), CurScope); - - Scope *OldScope = CurScope; - CurScope = OldScope->getParent(); - - if (NumCachedScopes == ScopeCacheSize) - delete OldScope; - else - ScopeCache[NumCachedScopes++] = OldScope; -} - - - - -//===----------------------------------------------------------------------===// -// C99 6.9: External Definitions. -//===----------------------------------------------------------------------===// - -Parser::~Parser() { - // If we still have scopes active, delete the scope tree. - delete CurScope; - - // Free the scope cache. - for (unsigned i = 0, e = NumCachedScopes; i != e; ++i) - delete ScopeCache[i]; -} - -/// Initialize - Warm up the parser. -/// -void Parser::Initialize() { - // Prime the lexer look-ahead. - ConsumeToken(); - - // Create the translation unit scope. Install it as the current scope. - assert(CurScope == 0 && "A scope is already active?"); - EnterScope(Scope::DeclScope); - Actions.ActOnTranslationUnitScope(Tok.getLocation(), CurScope); - - if (Tok.is(tok::eof) && - !getLang().CPlusPlus) // Empty source file is an extension in C - Diag(Tok, diag::ext_empty_source_file); - - // Initialization for Objective-C context sensitive keywords recognition. - // Referenced in Parser::ParseObjCTypeQualifierList. - if (getLang().ObjC1) { - ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in"); - ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out"); - ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout"); - ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway"); - ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy"); - ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); - } - if (getLang().ObjC2) { - ObjCPropertyAttrs[objc_readonly] = &PP.getIdentifierTable().get("readonly"); - ObjCPropertyAttrs[objc_getter] = &PP.getIdentifierTable().get("getter"); - ObjCPropertyAttrs[objc_setter] = &PP.getIdentifierTable().get("setter"); - ObjCPropertyAttrs[objc_assign] = &PP.getIdentifierTable().get("assign"); - ObjCPropertyAttrs[objc_readwrite] = - &PP.getIdentifierTable().get("readwrite"); - ObjCPropertyAttrs[objc_retain] = &PP.getIdentifierTable().get("retain"); - ObjCPropertyAttrs[objc_copy] = &PP.getIdentifierTable().get("copy"); - ObjCPropertyAttrs[objc_nonatomic] = - &PP.getIdentifierTable().get("nonatomic"); - ObjCForCollectionInKW = &PP.getIdentifierTable().get("in"); - } -} - -/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the -/// action tells us to. This returns true if the EOF was encountered. -bool Parser::ParseTopLevelDecl(DeclTy*& Result) { - Result = 0; - if (Tok.is(tok::eof)) return true; - - Result = ParseExternalDeclaration(); - return false; -} - -/// Finalize - Shut down the parser. -/// -void Parser::Finalize() { - ExitScope(); - assert(CurScope == 0 && "Scope imbalance!"); -} - -/// ParseTranslationUnit: -/// translation-unit: [C99 6.9] -/// external-declaration -/// translation-unit external-declaration -void Parser::ParseTranslationUnit() { - Initialize(); - - DeclTy *Res; - while (!ParseTopLevelDecl(Res)) - /*parse them all*/; - - Finalize(); -} - -/// ParseExternalDeclaration: -/// external-declaration: [C99 6.9] -/// function-definition -/// declaration -/// [EXT] ';' -/// [GNU] asm-definition -/// [GNU] __extension__ external-declaration -/// [OBJC] objc-class-definition -/// [OBJC] objc-class-declaration -/// [OBJC] objc-alias-declaration -/// [OBJC] objc-protocol-definition -/// [OBJC] objc-method-definition -/// [OBJC] @end -/// -/// [GNU] asm-definition: -/// simple-asm-expr ';' -/// -Parser::DeclTy *Parser::ParseExternalDeclaration() { - switch (Tok.getKind()) { - case tok::semi: - Diag(Tok, diag::ext_top_level_semi); - ConsumeToken(); - // TODO: Invoke action for top-level semicolon. - return 0; - case tok::kw___extension__: { - ConsumeToken(); - // FIXME: Disable extension warnings. - DeclTy *RV = ParseExternalDeclaration(); - // FIXME: Restore extension warnings. - return RV; - } - case tok::kw_asm: { - ExprResult Result = ParseSimpleAsm(); - - ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - "top-level asm block"); - - if (!Result.isInvalid) - return Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), Result.Val); - } - case tok::at: - // @ is not a legal token unless objc is enabled, no need to check. - return ParseObjCAtDirectives(); - case tok::minus: - case tok::plus: - if (getLang().ObjC1) - return ParseObjCMethodDefinition(); - else { - Diag(Tok, diag::err_expected_external_declaration); - ConsumeToken(); - } - return 0; - case tok::kw_namespace: - case tok::kw_typedef: - // A function definition cannot start with a these keywords. - return ParseDeclaration(Declarator::FileContext); - default: - // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(); - } -} - -/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or -/// a declaration. We can't tell which we have until we read up to the -/// compound-statement in function-definition. -/// -/// function-definition: [C99 6.9.1] -/// declaration-specifiers[opt] declarator declaration-list[opt] -/// compound-statement -/// declaration: [C99 6.7] -/// declaration-specifiers init-declarator-list[opt] ';' -/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] -/// [OMP] threadprivate-directive [TODO] -/// -Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { - // Parse the common declaration-specifiers piece. - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - - // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" - // declaration-specifiers init-declarator-list[opt] ';' - if (Tok.is(tok::semi)) { - ConsumeToken(); - return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); - } - - // ObjC2 allows prefix attributes on class interfaces. - if (getLang().ObjC2 && Tok.is(tok::at)) { - SourceLocation AtLoc = ConsumeToken(); // the "@" - if (!Tok.isObjCAtKeyword(tok::objc_interface)) { - Diag(Tok, diag::err_objc_expected_property_attr);//FIXME:better diagnostic - SkipUntil(tok::semi); // FIXME: better skip? - return 0; - } - const char *PrevSpec = 0; - if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec)) - Diag(AtLoc, diag::err_invalid_decl_spec_combination, PrevSpec); - return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); - } - - // If the declspec consisted only of 'extern' and we have a string - // literal following it, this must be a C++ linkage specifier like - // 'extern "C"'. - if (Tok.is(tok::string_literal) && getLang().CPlusPlus && - DS.getStorageClassSpec() == DeclSpec::SCS_extern && - DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) - return ParseLinkage(Declarator::FileContext); - - // Parse the first declarator. - Declarator DeclaratorInfo(DS, Declarator::FileContext); - ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? - if (DeclaratorInfo.getIdentifier() == 0) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return 0; - } - - // If the declarator is the start of a function definition, handle it. - if (Tok.is(tok::equal) || // int X()= -> not a function def - Tok.is(tok::comma) || // int X(), -> not a function def - Tok.is(tok::semi) || // int X(); -> not a function def - Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def - Tok.is(tok::kw___attribute)) { // int X() __attr__ -> not a function def - // FALL THROUGH. - } else if (DeclaratorInfo.isFunctionDeclarator() && - (Tok.is(tok::l_brace) || // int X() {} - isDeclarationSpecifier())) { // int X(f) int f; {} - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - if (Tok.is(tok::l_brace)) { - // This recovery skips the entire function body. It would be nice - // to simply call ParseFunctionDefintion() below, however Sema - // assumes the declarator represents a function, not a typedef. - ConsumeBrace(); - SkipUntil(tok::r_brace, true); - } else { - SkipUntil(tok::semi); - } - return 0; - } - return ParseFunctionDefinition(DeclaratorInfo); - } else { - if (DeclaratorInfo.isFunctionDeclarator()) - Diag(Tok, diag::err_expected_fn_body); - else - Diag(Tok, diag::err_expected_after_declarator); - SkipUntil(tok::semi); - return 0; - } - - // Parse the init-declarator-list for a normal declaration. - return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); -} - -/// ParseFunctionDefinition - We parsed and verified that the specified -/// Declarator is well formed. If this is a K&R-style function, read the -/// parameters declaration-list, then start the compound-statement. -/// -/// declaration-specifiers[opt] declarator declaration-list[opt] -/// compound-statement [TODO] -/// -Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) { - const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); - assert(FnTypeInfo.Kind == DeclaratorChunk::Function && - "This isn't a function declarator!"); - const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun; - - // If this declaration was formed with a K&R-style identifier list for the - // arguments, parse declarations for all of the args next. - // int foo(a,b) int a; float b; {} - if (!FTI.hasPrototype && FTI.NumArgs != 0) - ParseKNRParamDeclarations(D); - - // We should have an opening brace now. - if (Tok.isNot(tok::l_brace)) { - Diag(Tok, diag::err_expected_fn_body); - - // Skip over garbage, until we get to '{'. Don't eat the '{'. - SkipUntil(tok::l_brace, true, true); - - // If we didn't find the '{', bail out. - if (Tok.isNot(tok::l_brace)) - return 0; - } - - SourceLocation BraceLoc = Tok.getLocation(); - - // Enter a scope for the function body. - EnterScope(Scope::FnScope|Scope::DeclScope); - - // Tell the actions module that we have entered a function definition with the - // specified Declarator for the function. - DeclTy *Res = Actions.ActOnStartOfFunctionDef(CurScope, D); - - return ParseFunctionStatementBody(Res, BraceLoc, BraceLoc); -} - -/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides -/// types for a function with a K&R-style identifier list for arguments. -void Parser::ParseKNRParamDeclarations(Declarator &D) { - // We know that the top-level of this declarator is a function. - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; - - // Read all the argument declarations. - while (isDeclarationSpecifier()) { - SourceLocation DSStart = Tok.getLocation(); - - // Parse the common declaration-specifiers piece. - DeclSpec DS; - ParseDeclarationSpecifiers(DS); - - // C99 6.9.1p6: 'each declaration in the declaration list shall have at - // least one declarator'. - // NOTE: GCC just makes this an ext-warn. It's not clear what it does with - // the declarations though. It's trivial to ignore them, really hard to do - // anything else with them. - if (Tok.is(tok::semi)) { - Diag(DSStart, diag::err_declaration_does_not_declare_param); - ConsumeToken(); - continue; - } - - // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other - // than register. - if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && - DS.getStorageClassSpec() != DeclSpec::SCS_register) { - Diag(DS.getStorageClassSpecLoc(), - diag::err_invalid_storage_class_in_func_decl); - DS.ClearStorageClassSpecs(); - } - if (DS.isThreadSpecified()) { - Diag(DS.getThreadSpecLoc(), - diag::err_invalid_storage_class_in_func_decl); - DS.ClearStorageClassSpecs(); - } - - // Parse the first declarator attached to this declspec. - Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext); - ParseDeclarator(ParmDeclarator); - - // Handle the full declarator list. - while (1) { - DeclTy *AttrList; - // If attributes are present, parse them. - if (Tok.is(tok::kw___attribute)) - // FIXME: attach attributes too. - AttrList = ParseAttributes(); - - // Ask the actions module to compute the type for this declarator. - Action::TypeResult TR = - Actions.ActOnParamDeclaratorType(CurScope, ParmDeclarator); - - if (!TR.isInvalid && - // A missing identifier has already been diagnosed. - ParmDeclarator.getIdentifier()) { - - // Scan the argument list looking for the correct param to apply this - // type. - for (unsigned i = 0; ; ++i) { - // C99 6.9.1p6: those declarators shall declare only identifiers from - // the identifier list. - if (i == FTI.NumArgs) { - Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param, - ParmDeclarator.getIdentifier()->getName()); - break; - } - - if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) { - // Reject redefinitions of parameters. - if (FTI.ArgInfo[i].TypeInfo) { - Diag(ParmDeclarator.getIdentifierLoc(), - diag::err_param_redefinition, - ParmDeclarator.getIdentifier()->getName()); - } else { - FTI.ArgInfo[i].TypeInfo = TR.Val; - } - break; - } - } - } - - // If we don't have a comma, it is either the end of the list (a ';') or - // an error, bail out. - if (Tok.isNot(tok::comma)) - break; - - // Consume the comma. - ConsumeToken(); - - // Parse the next declarator. - ParmDeclarator.clear(); - ParseDeclarator(ParmDeclarator); - } - - if (Tok.is(tok::semi)) { - ConsumeToken(); - } else { - Diag(Tok, diag::err_parse_error); - // Skip to end of block or statement - SkipUntil(tok::semi, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - } - } - - // The actions module must verify that all arguments were declared. -} - - -/// ParseAsmStringLiteral - This is just a normal string-literal, but is not -/// allowed to be a wide string, and is not subject to character translation. -/// -/// [GNU] asm-string-literal: -/// string-literal -/// -Parser::ExprResult Parser::ParseAsmStringLiteral() { - if (!isTokenStringLiteral()) { - Diag(Tok, diag::err_expected_string_literal); - return true; - } - - ExprResult Res = ParseStringLiteralExpression(); - if (Res.isInvalid) return true; - - // TODO: Diagnose: wide string literal in 'asm' - - return Res; -} - -/// ParseSimpleAsm -/// -/// [GNU] simple-asm-expr: -/// 'asm' '(' asm-string-literal ')' -/// -Parser::ExprResult Parser::ParseSimpleAsm() { - assert(Tok.is(tok::kw_asm) && "Not an asm!"); - SourceLocation Loc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - Diag(Tok, diag::err_expected_lparen_after, "asm"); - return 0; - } - - ConsumeParen(); - - ExprResult Result = ParseAsmStringLiteral(); - - MatchRHSPunctuation(tok::r_paren, Loc); - - return Result; -} - diff --git a/clang/Rewrite/Makefile b/clang/Rewrite/Makefile deleted file mode 100644 index e5453e9a389..00000000000 --- a/clang/Rewrite/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -##===- clang/Rewrite/Makefile ------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements code transformation / rewriting facilities. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangRewrite -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/Rewrite/Rewriter.cpp b/clang/Rewrite/Rewriter.cpp deleted file mode 100644 index 440d1d39fd5..00000000000 --- a/clang/Rewrite/Rewriter.cpp +++ /dev/null @@ -1,258 +0,0 @@ -//===--- Rewriter.cpp - Code rewriting interface --------------------------===// -// -// 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 Rewriter class, which is used for code -// transformations. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Rewriter.h" -#include "clang/AST/Stmt.h" -#include "clang/Lex/Lexer.h" -#include "clang/Basic/SourceManager.h" -#include -using namespace clang; - -/// getMappedOffset - Given an offset into the original SourceBuffer that this -/// RewriteBuffer is based on, map it into the offset space of the -/// RewriteBuffer. -unsigned RewriteBuffer::getMappedOffset(unsigned OrigOffset, - bool AfterInserts) const { - unsigned ResultOffset = OrigOffset; - unsigned DeltaIdx = 0; - - // Move past any deltas that are relevant. - // FIXME: binary search. - for (; DeltaIdx != Deltas.size() && - Deltas[DeltaIdx].FileLoc < OrigOffset; ++DeltaIdx) - ResultOffset += Deltas[DeltaIdx].Delta; - - if (AfterInserts && DeltaIdx != Deltas.size() && - OrigOffset == Deltas[DeltaIdx].FileLoc) - ResultOffset += Deltas[DeltaIdx].Delta; - return ResultOffset; -} - -/// AddDelta - When a change is made that shifts around the text buffer, this -/// method is used to record that info. -void RewriteBuffer::AddDelta(unsigned OrigOffset, int Change) { - assert(Change != 0 && "Not changing anything"); - unsigned DeltaIdx = 0; - - // Skip over any unrelated deltas. - for (; DeltaIdx != Deltas.size() && - Deltas[DeltaIdx].FileLoc < OrigOffset; ++DeltaIdx) - ; - - // If there is no a delta for this offset, insert a new delta record. - if (DeltaIdx == Deltas.size() || OrigOffset != Deltas[DeltaIdx].FileLoc) { - // If this is a removal, check to see if this can be folded into - // a delta at the end of the deletion. For example, if we have: - // ABCXDEF (X inserted after C) and delete C, we want to end up with no - // delta because X basically replaced C. - if (Change < 0 && DeltaIdx != Deltas.size() && - OrigOffset-Change == Deltas[DeltaIdx].FileLoc) { - // Adjust the start of the delta to be the start of the deleted region. - Deltas[DeltaIdx].FileLoc += Change; - Deltas[DeltaIdx].Delta += Change; - - // If the delta becomes a noop, remove it. - if (Deltas[DeltaIdx].Delta == 0) - Deltas.erase(Deltas.begin()+DeltaIdx); - return; - } - - // Otherwise, create an entry and return. - Deltas.insert(Deltas.begin()+DeltaIdx, - SourceDelta::get(OrigOffset, Change)); - return; - } - - // Otherwise, we found a delta record at this offset, adjust it. - Deltas[DeltaIdx].Delta += Change; - - // If it is now dead, remove it. - if (Deltas[DeltaIdx].Delta == 0) - Deltas.erase(Deltas.begin()+DeltaIdx); -} - - -void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { - // Nothing to remove, exit early. - if (Size == 0) return; - - unsigned RealOffset = getMappedOffset(OrigOffset, true); - assert(RealOffset+Size < Buffer.size() && "Invalid location"); - - // Remove the dead characters. - RewriteRope::iterator I = Buffer.getAtOffset(RealOffset); - Buffer.erase(I, I+Size); - - // Add a delta so that future changes are offset correctly. - AddDelta(OrigOffset, -Size); -} - -void RewriteBuffer::InsertText(unsigned OrigOffset, - const char *StrData, unsigned StrLen) { - // Nothing to insert, exit early. - if (StrLen == 0) return; - - unsigned RealOffset = getMappedOffset(OrigOffset, true); - assert(RealOffset <= Buffer.size() && "Invalid location"); - - // Insert the new characters. - Buffer.insert(Buffer.getAtOffset(RealOffset), StrData, StrData+StrLen); - - // Add a delta so that future changes are offset correctly. - AddDelta(OrigOffset, StrLen); -} - -/// ReplaceText - This method replaces a range of characters in the input -/// buffer with a new string. This is effectively a combined "remove/insert" -/// operation. -void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, - const char *NewStr, unsigned NewLength) { - unsigned RealOffset = getMappedOffset(OrigOffset, true); - assert(RealOffset+OrigLength <= Buffer.size() && "Invalid location"); - - // Overwrite the common piece. - unsigned CommonLength = std::min(OrigLength, NewLength); - std::copy(NewStr, NewStr+CommonLength, Buffer.getAtOffset(RealOffset)); - - // If replacing without shifting around, just overwrite the text. - if (OrigLength == NewLength) - return; - - // If inserting more than existed before, this is like an insertion. - if (NewLength > OrigLength) { - Buffer.insert(Buffer.getAtOffset(RealOffset+OrigLength), - NewStr+OrigLength, NewStr+NewLength); - } else { - // If inserting less than existed before, this is like a removal. - RewriteRope::iterator I = Buffer.getAtOffset(RealOffset+NewLength); - Buffer.erase(I, I+(OrigLength-NewLength)); - } - AddDelta(OrigOffset, NewLength-OrigLength); -} - - -//===----------------------------------------------------------------------===// -// Rewriter class -//===----------------------------------------------------------------------===// - -/// getRangeSize - Return the size in bytes of the specified range if they -/// are in the same file. If not, this returns -1. -int Rewriter::getRangeSize(SourceRange Range) const { - if (!isRewritable(Range.getBegin()) || - !isRewritable(Range.getEnd())) return -1; - - unsigned StartOff, StartFileID; - unsigned EndOff , EndFileID; - - StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); - - if (StartFileID != EndFileID) - return -1; - - // If edits have been made to this buffer, the delta between the range may - // have changed. - std::map::const_iterator I = - RewriteBuffers.find(StartFileID); - if (I != RewriteBuffers.end()) { - const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, true); - StartOff = RB.getMappedOffset(StartOff); - } - - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token. - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr); - - return EndOff-StartOff; -} - - -unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, - unsigned &FileID) const { - std::pair V = SourceMgr->getDecomposedFileLoc(Loc); - FileID = V.first; - return V.second; -} - - -/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. -/// -RewriteBuffer &Rewriter::getEditBuffer(unsigned FileID) { - std::map::iterator I = - RewriteBuffers.lower_bound(FileID); - if (I != RewriteBuffers.end() && I->first == FileID) - return I->second; - I = RewriteBuffers.insert(I, std::make_pair(FileID, RewriteBuffer())); - - std::pair MB = SourceMgr->getBufferData(FileID); - I->second.Initialize(MB.first, MB.second); - - return I->second; -} - -/// InsertText - Insert the specified string at the specified location in the -/// original buffer. -bool Rewriter::InsertText(SourceLocation Loc, - const char *StrData, unsigned StrLen) { - if (!isRewritable(Loc)) return true; - unsigned FileID; - unsigned StartOffs = getLocationOffsetAndFileID(Loc, FileID); - getEditBuffer(FileID).InsertText(StartOffs, StrData, StrLen); - return false; -} - -/// RemoveText - Remove the specified text region. -bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) { - if (!isRewritable(Start)) return true; - unsigned FileID; - unsigned StartOffs = getLocationOffsetAndFileID(Start, FileID); - getEditBuffer(FileID).RemoveText(StartOffs, Length); - return false; -} - -/// ReplaceText - This method replaces a range of characters in the input -/// buffer with a new string. This is effectively a combined "remove/insert" -/// operation. -bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, - const char *NewStr, unsigned NewLength) { - if (!isRewritable(Start)) return true; - unsigned StartFileID; - unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); - - getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, - NewStr, NewLength); - return false; -} - -/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty -/// printer to generate the replacement code. This returns true if the input -/// could not be rewritten, or false if successful. -bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { - // Measaure the old text. - int Size = getRangeSize(From->getSourceRange()); - if (Size == -1) - return true; - - // Get the new text. - std::ostringstream S; - To->printPretty(S); - const std::string &Str = S.str(); - - ReplaceText(From->getLocStart(), Size, &Str[0], Str.size()); - return false; -} - - diff --git a/clang/Sema/Makefile b/clang/Sema/Makefile deleted file mode 100644 index 22ca9c7079a..00000000000 --- a/clang/Sema/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -##===- clang/Sema/Makefile ---------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements the semantic analyzer and AST builder library for the -# C-Language front-end. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME := clangSEMA -BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti - -CPPFLAGS += -I$(PROJ_SRC_DIR)/../include - -include $(LEVEL)/Makefile.common - diff --git a/clang/Sema/ParseAST.cpp b/clang/Sema/ParseAST.cpp deleted file mode 100644 index 364b0729100..00000000000 --- a/clang/Sema/ParseAST.cpp +++ /dev/null @@ -1,69 +0,0 @@ -//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the clang::ParseAST method. -// -//===----------------------------------------------------------------------===// - -#include "clang/Sema/ParseAST.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/ASTConsumer.h" -#include "Sema.h" -#include "clang/Parse/Action.h" -#include "clang/Parse/Parser.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Public interface to the file -//===----------------------------------------------------------------------===// - -/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as -/// the file is parsed. This takes ownership of the ASTConsumer and -/// ultimately deletes it. -void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, bool PrintStats) { - // Collect global stats on Decls/Stmts (until we have a module streamer). - if (PrintStats) { - Decl::CollectingStats(true); - Stmt::CollectingStats(true); - } - - ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(), - PP.getIdentifierTable(), PP.getSelectorTable()); - - Parser P(PP, *new Sema(PP, Context, *Consumer)); - PP.EnterMainSourceFile(); - - // Initialize the parser. - P.Initialize(); - - Consumer->Initialize(Context); - - Parser::DeclTy *ADecl; - while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. - if (ADecl) - Consumer->HandleTopLevelDecl(static_cast(ADecl)); - }; - - if (PrintStats) { - fprintf(stderr, "\nSTATISTICS:\n"); - P.getActions().PrintStats(); - Context.PrintStats(); - Decl::PrintStats(); - Stmt::PrintStats(); - Consumer->PrintStats(); - - Decl::CollectingStats(false); - Stmt::CollectingStats(false); - } - - delete Consumer; -} diff --git a/clang/Sema/Sema.cpp b/clang/Sema/Sema.cpp deleted file mode 100644 index 4bd04e3a1a5..00000000000 --- a/clang/Sema/Sema.cpp +++ /dev/null @@ -1,222 +0,0 @@ -//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the actions class which performs semantic analysis and -// builds an AST out of a parse stream. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTContext.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Parse/Scope.h" - -using namespace clang; - -bool Sema::isBuiltinObjCType(TypedefDecl *TD) { - const char *typeName = TD->getIdentifier()->getName(); - return strcmp(typeName, "id") == 0 || strcmp(typeName, "Class") == 0 || - strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0; -} - -bool Sema::isObjCObjectPointerType(QualType type) const { - if (!type->isPointerType() && !type->isObjCQualifiedIdType()) - return false; - if (type == Context.getObjCIdType() || type == Context.getObjCClassType() || - type->isObjCQualifiedIdType()) - return true; - - if (type->isPointerType()) { - PointerType *pointerType = static_cast(type.getTypePtr()); - type = pointerType->getPointeeType(); - } - return (type->isObjCInterfaceType() || type->isObjCQualifiedIdType()); -} - -void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { - TUScope = S; - if (!PP.getLangOptions().ObjC1) return; - - TypedefType *t; - - // Add the built-in ObjC types. - t = cast(Context.getObjCIdType().getTypePtr()); - t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); - TUScope->AddDecl(t->getDecl()); - t = cast(Context.getObjCClassType().getTypePtr()); - t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); - TUScope->AddDecl(t->getDecl()); - ObjCInterfaceType *it = cast(Context.getObjCProtoType()); - ObjCInterfaceDecl *IDecl = it->getDecl(); - IDecl->getIdentifier()->setFETokenInfo(IDecl); - TUScope->AddDecl(IDecl); - - // Synthesize "typedef struct objc_selector *SEL;" - RecordDecl *SelTag = RecordDecl::Create(Context, Decl::Struct, - SourceLocation(), - &Context.Idents.get("objc_selector"), - 0); - SelTag->getIdentifier()->setFETokenInfo(SelTag); - TUScope->AddDecl(SelTag); - - QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); - TypedefDecl *SelTypedef = TypedefDecl::Create(Context, SourceLocation(), - &Context.Idents.get("SEL"), - SelT, 0); - SelTypedef->getIdentifier()->setFETokenInfo(SelTypedef); - TUScope->AddDecl(SelTypedef); - Context.setObjCSelType(SelTypedef); -} - -Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer) - : PP(pp), Context(ctxt), Consumer(consumer), - CurFunctionDecl(0), CurMethodDecl(0) { - - // Get IdentifierInfo objects for known functions for which we - // do extra checking. - IdentifierTable &IT = PP.getIdentifierTable(); - - KnownFunctionIDs[id_printf] = &IT.get("printf"); - KnownFunctionIDs[id_fprintf] = &IT.get("fprintf"); - KnownFunctionIDs[id_sprintf] = &IT.get("sprintf"); - KnownFunctionIDs[id_snprintf] = &IT.get("snprintf"); - KnownFunctionIDs[id_asprintf] = &IT.get("asprintf"); - KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf"); - KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf"); - KnownFunctionIDs[id_vfprintf] = &IT.get("vfprintf"); - KnownFunctionIDs[id_vsprintf] = &IT.get("vsprintf"); - KnownFunctionIDs[id_vprintf] = &IT.get("vprintf"); - - // FIXME: Move this initialization up to Sema::ActOnTranslationUnitScope() - // and make sure the decls get inserted into TUScope! - if (PP.getLangOptions().ObjC1) { - // Synthesize "typedef struct objc_class *Class;" - RecordDecl *ClassTag = RecordDecl::Create(Context, Decl::Struct, - SourceLocation(), - &IT.get("objc_class"), 0); - QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); - TypedefDecl *ClassTypedef = - TypedefDecl::Create(Context, SourceLocation(), - &Context.Idents.get("Class"), ClassT, 0); - Context.setObjCClassType(ClassTypedef); - - // Synthesize "@class Protocol; - ObjCInterfaceDecl *ProtocolDecl = new ObjCInterfaceDecl(SourceLocation(), 0, - &Context.Idents.get("Protocol"), true); - Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); - - // Synthesize "typedef struct objc_object { Class isa; } *id;" - RecordDecl *ObjectTag = - RecordDecl::Create(Context, Decl::Struct, SourceLocation(), - &IT.get("objc_object"), 0); - FieldDecl *IsaDecl = new FieldDecl(SourceLocation(), 0, - Context.getObjCClassType()); - ObjectTag->defineBody(&IsaDecl, 1); - QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); - TypedefDecl *IdTypedef = TypedefDecl::Create(Context, SourceLocation(), - &Context.Idents.get("id"), - ObjT, 0); - Context.setObjCIdType(IdTypedef); - } - TUScope = 0; -} - -/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. -/// If there is already an implicit cast, merge into the existing one. -void Sema::ImpCastExprToType(Expr *&Expr, QualType Type) { - if (Expr->getType().getCanonicalType() == Type.getCanonicalType()) return; - - if (ImplicitCastExpr *ImpCast = dyn_cast(Expr)) - ImpCast->setType(Type); - else - Expr = new ImplicitCastExpr(Type, Expr); -} - - - -void Sema::DeleteExpr(ExprTy *E) { - delete static_cast(E); -} -void Sema::DeleteStmt(StmtTy *S) { - delete static_cast(S); -} - -//===----------------------------------------------------------------------===// -// Helper functions. -//===----------------------------------------------------------------------===// - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID) { - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) { - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2) { - std::string MsgArr[] = { Msg1, Msg2 }; - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) { - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, &Range,1); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, - SourceRange Range) { - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, &Range,1); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2, SourceRange Range) { - std::string MsgArr[] = { Msg1, Msg2 }; - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2, &Range, 1); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2, const std::string &Msg3, - SourceRange R1) { - std::string MsgArr[] = { Msg1, Msg2, Msg3 }; - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 3, &R1, 1); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, - SourceRange R1, SourceRange R2) { - SourceRange RangeArr[] = { R1, R2 }; - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, RangeArr, 2); - return true; -} - -bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, - SourceRange R1, SourceRange R2) { - SourceRange RangeArr[] = { R1, R2 }; - PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, RangeArr, 2); - return true; -} - -bool Sema::Diag(SourceLocation Range, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2, SourceRange R1, SourceRange R2) { - std::string MsgArr[] = { Msg1, Msg2 }; - SourceRange RangeArr[] = { R1, R2 }; - PP.getDiagnostics().Report(PP.getFullLoc(Range),DiagID, MsgArr,2,RangeArr, 2); - return true; -} - -const LangOptions &Sema::getLangOptions() const { - return PP.getLangOptions(); -} diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h deleted file mode 100644 index fc81781911c..00000000000 --- a/clang/Sema/Sema.h +++ /dev/null @@ -1,823 +0,0 @@ -//===--- Sema.h - Semantic Analysis & AST Building --------------*- 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 Sema class, which performs semantic analysis and -// builds ASTs. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_SEMA_H -#define LLVM_CLANG_AST_SEMA_H - -#include "clang/Parse/Action.h" -#include "clang/Parse/DeclSpec.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include -#include - -namespace llvm { - class APSInt; -} - -namespace clang { - class ASTContext; - class ASTConsumer; - class Preprocessor; - class Decl; - class ScopedDecl; - class Expr; - class InitListExpr; - class CallExpr; - class VarDecl; - class ParmVarDecl; - class TypedefDecl; - class FunctionDecl; - class QualType; - struct LangOptions; - class Token; - class IntegerLiteral; - class StringLiteral; - class ArrayType; - class LabelStmt; - class SwitchStmt; - class OCUVectorType; - class TypedefDecl; - class ObjCInterfaceDecl; - class ObjCProtocolDecl; - class ObjCImplementationDecl; - class ObjCCategoryImplDecl; - class ObjCCategoryDecl; - class ObjCIvarDecl; - class ObjCMethodDecl; - -/// Sema - This implements semantic analysis and AST building for C. -class Sema : public Action { - Preprocessor &PP; - ASTContext &Context; - ASTConsumer &Consumer; - - /// CurFunctionDecl - If inside of a function body, this contains a pointer to - /// the function decl for the function being parsed. - FunctionDecl *CurFunctionDecl; - - /// CurMethodDecl - If inside of a method body, this contains a pointer to - /// the method decl for the method being parsed. - ObjCMethodDecl *CurMethodDecl; - - /// LabelMap - This is a mapping from label identifiers to the LabelStmt for - /// it (which acts like the label decl in some ways). Forward referenced - /// labels have a LabelStmt created for them with a null location & SubStmt. - llvm::DenseMap LabelMap; - - llvm::SmallVector SwitchStack; - - /// OCUVectorDecls - This is a list all the OCU vector types. This allows - /// us to associate a raw vector type with one of the OCU type names. - /// This is only necessary for issuing pretty diagnostics. - llvm::SmallVector OCUVectorDecls; - - /// ObjCImplementations - Keep track of all of the classes with - /// @implementation's, so that we can emit errors on duplicates. - llvm::DenseMap ObjCImplementations; - - /// ObjCProtocols - Keep track of all protocol declarations declared - /// with @protocol keyword, so that we can emit errors on duplicates and - /// find the declarations when needed. - llvm::DenseMap ObjCProtocols; - - // Enum values used by KnownFunctionIDs (see below). - enum { - id_printf, - id_fprintf, - id_sprintf, - id_snprintf, - id_asprintf, - id_vsnprintf, - id_vasprintf, - id_vfprintf, - id_vsprintf, - id_vprintf, - id_num_known_functions - }; - - /// KnownFunctionIDs - This is a list of IdentifierInfo objects to a set - /// of known functions used by the semantic analysis to do various - /// kinds of checking (e.g. checking format string errors in printf calls). - /// This list is populated upon the creation of a Sema object. - IdentifierInfo* KnownFunctionIDs[ id_num_known_functions ]; - - /// Translation Unit Scope - useful to Objective-C actions that need - /// to lookup file scope declarations in the "ordinary" C decl namespace. - /// For example, user-defined classes, built-in "id" type, etc. - Scope *TUScope; - - /// ObjCMethodList - a linked list of methods with different signatures. - struct ObjCMethodList { - ObjCMethodDecl *Method; - ObjCMethodList *Next; - - ObjCMethodList() { - Method = 0; - Next = 0; - } - ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { - Method = M; - Next = C; - } - }; - /// Instance/Factory Method Pools - allows efficient lookup when typechecking - /// messages to "id". We need to maintain a list, since selectors can have - /// differing signatures across classes. In Cocoa, this happens to be - /// extremely uncommon (only 1% of selectors are "overloaded"). - llvm::DenseMap InstanceMethodPool; - llvm::DenseMap FactoryMethodPool; -public: - Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer); - - const LangOptions &getLangOptions() const; - - /// The primitive diagnostic helpers - always returns true, which simplifies - /// error handling (i.e. less code). - bool Diag(SourceLocation Loc, unsigned DiagID); - bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg); - bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2); - - /// More expressive diagnostic helpers for expressions (say that 6 times:-) - bool Diag(SourceLocation Loc, unsigned DiagID, SourceRange R1); - bool Diag(SourceLocation Loc, unsigned DiagID, - SourceRange R1, SourceRange R2); - bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, - SourceRange R1); - bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, - SourceRange R1, SourceRange R2); - bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2, SourceRange R1); - bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, - const std::string &Msg2, const std::string &Msg3, SourceRange R1); - bool Diag(SourceLocation Loc, unsigned DiagID, - const std::string &Msg1, const std::string &Msg2, - SourceRange R1, SourceRange R2); - - virtual void DeleteExpr(ExprTy *E); - virtual void DeleteStmt(StmtTy *S); - - //===--------------------------------------------------------------------===// - // Type Analysis / Processing: SemaType.cpp. - // - QualType ConvertDeclSpecToType(DeclSpec &DS); - AttributeList *ProcessTypeAttributes(QualType &Result, AttributeList *AL); - QualType GetTypeForDeclarator(Declarator &D, Scope *S); - - - QualType ObjCGetTypeForMethodDefinition(DeclTy *D); - - - virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); - - virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D); -private: - //===--------------------------------------------------------------------===// - // Symbol table / Decl tracking callbacks: SemaDecl.cpp. - // - virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const; - virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup); - void AddInitializerToDecl(DeclTy *dcl, ExprTy *init); - virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group); - - virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D); - virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D); - - virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body); - virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace, - SourceLocation RBrace, const char *Lang, - unsigned StrSize, DeclTy *D); - virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprTy *expr); - - /// Scope actions. - virtual void ActOnPopScope(SourceLocation Loc, Scope *S); - virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); - - /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with - /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); - - virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, - SourceLocation KWLoc, IdentifierInfo *Name, - SourceLocation NameLoc, AttributeList *Attr); - virtual DeclTy *ActOnField(Scope *S, DeclTy *TagDecl,SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth); - - // This is used for both record definitions and ObjC interface declarations. - virtual void ActOnFields(Scope* S, - SourceLocation RecLoc, DeclTy *TagDecl, - DeclTy **Fields, unsigned NumFields, - SourceLocation LBrac, SourceLocation RBrac, - tok::ObjCKeywordKind *visibility = 0); - virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl, - DeclTy *LastEnumConstant, - SourceLocation IdLoc, IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *Val); - virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl, - DeclTy **Elements, unsigned NumElements); -private: - /// Subroutines of ActOnDeclarator(). - TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - ScopedDecl *LastDecl); - TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *Old); - FunctionDecl *MergeFunctionDecl(FunctionDecl *New, ScopedDecl *Old); - VarDecl *MergeVarDecl(VarDecl *New, ScopedDecl *Old); - - /// More parsing and symbol table subroutines... - ParmVarDecl *ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, - Scope *FnBodyScope); - ScopedDecl *LookupScopedDecl(IdentifierInfo *II, unsigned NSI, - SourceLocation IdLoc, Scope *S); - ScopedDecl *LookupInterfaceDecl(IdentifierInfo *II); - ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); - ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S); - ScopedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, - Scope *S); - // Decl attributes - this routine is the top level dispatcher. - void HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix, - AttributeList *declarator_postfix); - void HandleDeclAttribute(Decl *New, AttributeList *rawAttr); - - /// HandleAddressSpaceTypeAttribute - this attribute is only applicable to - /// objects without automatic storage duration. - /// The raw attribute contains 1 argument, the id of the address space - /// for the type. - QualType HandleAddressSpaceTypeAttribute(QualType curType, - AttributeList *rawAttr); - - // HandleVectorTypeAttribute - this attribute is only applicable to - // integral and float scalars, although arrays, pointers, and function - // return values are allowed in conjunction with this construct. Aggregates - // with this attribute are invalid, even if they are of the same size as a - // corresponding scalar. - // The raw attribute should contain precisely 1 argument, the vector size - // for the variable, measured in bytes. If curType and rawAttr are well - // formed, this routine will return a new vector type. - QualType HandleVectorTypeAttribute(QualType curType, AttributeList *rawAttr); - void HandleOCUVectorTypeAttribute(TypedefDecl *d, AttributeList *rawAttr); - - void HandleAlignedAttribute(Decl *d, AttributeList *rawAttr); - void HandlePackedAttribute(Decl *d, AttributeList *rawAttr); - void HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr); - void HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr); - void HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr); - void HandleWeakAttribute(Decl *d, AttributeList *rawAttr); - void HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr); - void HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr); - void HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr); - void HandleNothrowAttribute(Decl *d, AttributeList *rawAttr); - void HandleFormatAttribute(Decl *d, AttributeList *rawAttr); - void HandleStdCallAttribute(Decl *d, AttributeList *rawAttr); - void HandleFastCallAttribute(Decl *d, AttributeList *rawAttr); - - void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl); - - /// CheckProtocolMethodDefs - This routine checks unimpletented methods - /// Declared in protocol, and those referenced by it. - void CheckProtocolMethodDefs(SourceLocation ImpLoc, - ObjCProtocolDecl *PDecl, - bool& IncompleteImpl, - const llvm::DenseSet &InsMap, - const llvm::DenseSet &ClsMap); - - /// CheckImplementationIvars - This routine checks if the instance variables - /// listed in the implelementation match those listed in the interface. - void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, - ObjCIvarDecl **Fields, unsigned nIvars, - SourceLocation Loc); - - /// ImplMethodsVsClassMethods - This is main routine to warn if any method - /// remains unimplemented in the @implementation class. - void ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, - ObjCInterfaceDecl* IDecl); - - /// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the - /// category interface is implemented in the category @implementation. - void ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl, - ObjCCategoryDecl *CatClassDecl); - /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns - /// true, or false, accordingly. - bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, - const ObjCMethodDecl *PrevMethod); - - /// isBuiltinObjCType - Returns true of the type is "id", "SEL", "Class" - /// or "Protocol". - bool isBuiltinObjCType(TypedefDecl *TD); - - /// isObjCObjectPointerType - Returns true if type is an objective-c pointer - /// to an object type; such as "id", "Class", Intf*, id

, etc. - bool isObjCObjectPointerType(QualType type) const; - - /// AddInstanceMethodToGlobalPool - All instance methods in a translation - /// unit are added to a global pool. This allows us to efficiently associate - /// a selector with a method declaraation for purposes of typechecking - /// messages sent to "id" (where the class of the object is unknown). - void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method); - - /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. - void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); - //===--------------------------------------------------------------------===// - // Statement Parsing Callbacks: SemaStmt.cpp. -public: - virtual StmtResult ActOnExprStmt(ExprTy *Expr); - - virtual StmtResult ActOnNullStmt(SourceLocation SemiLoc); - virtual StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, - StmtTy **Elts, unsigned NumElts, - bool isStmtExpr); - virtual StmtResult ActOnDeclStmt(DeclTy *Decl, SourceLocation StartLoc, - SourceLocation EndLoc); - virtual StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *LHSVal, - SourceLocation DotDotDotLoc, ExprTy *RHSVal, - SourceLocation ColonLoc, StmtTy *SubStmt); - virtual StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, - SourceLocation ColonLoc, StmtTy *SubStmt, - Scope *CurScope); - virtual StmtResult ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, - SourceLocation ColonLoc, StmtTy *SubStmt); - virtual StmtResult ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal, - StmtTy *ThenVal, SourceLocation ElseLoc, - StmtTy *ElseVal); - virtual StmtResult ActOnStartOfSwitchStmt(ExprTy *Cond); - virtual StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, - StmtTy *Switch, ExprTy *Body); - virtual StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, - StmtTy *Body); - virtual StmtResult ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body, - SourceLocation WhileLoc, ExprTy *Cond); - - virtual StmtResult ActOnForStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, - StmtTy *First, ExprTy *Second, ExprTy *Third, - SourceLocation RParenLoc, StmtTy *Body); - virtual StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, - SourceLocation LParenLoc, - StmtTy *First, ExprTy *Second, - SourceLocation RParenLoc, StmtTy *Body); - - virtual StmtResult ActOnGotoStmt(SourceLocation GotoLoc, - SourceLocation LabelLoc, - IdentifierInfo *LabelII); - virtual StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, - SourceLocation StarLoc, - ExprTy *DestExp); - virtual StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, - Scope *CurScope); - virtual StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope); - - virtual StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, - ExprTy *RetValExp); - - virtual StmtResult ActOnAsmStmt(SourceLocation AsmLoc, - bool IsSimple, - bool IsVolatile, - unsigned NumOutputs, - unsigned NumInputs, - std::string *Names, - ExprTy **Constraints, - ExprTy **Exprs, - ExprTy *AsmString, - unsigned NumClobbers, - ExprTy **Clobbers, - SourceLocation RParenLoc); - - virtual StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, - SourceLocation RParen, StmtTy *Parm, - StmtTy *Body, StmtTy *CatchList); - - virtual StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, - StmtTy *Body); - - virtual StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtTy *Try, - StmtTy *Catch, StmtTy *Finally); - - virtual StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, - StmtTy *Throw); - virtual StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, - ExprTy *SynchExpr, - StmtTy *SynchBody); - - //===--------------------------------------------------------------------===// - // Expression Parsing Callbacks: SemaExpr.cpp. - - // Primary Expressions. - virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen); - virtual ExprResult ActOnPreDefinedExpr(SourceLocation Loc, - tok::TokenKind Kind); - virtual ExprResult ActOnNumericConstant(const Token &); - virtual ExprResult ActOnCharacterConstant(const Token &); - virtual ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, - ExprTy *Val); - - /// ActOnStringLiteral - The specified tokens were lexed as pasted string - /// fragments (e.g. "foo" "bar" L"baz"). - virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks); - - // Binary/Unary Operators. 'Tok' is the token for the operator. - virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, - ExprTy *Input); - virtual ExprResult - ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, - SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc); - - virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc, - tok::TokenKind Kind, ExprTy *Input); - - virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, - ExprTy *Idx, SourceLocation RLoc); - virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - IdentifierInfo &Member); - - /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. - /// This provides the location of the left/right parens and a list of comma - /// locations. - virtual ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc, - ExprTy **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - - virtual ExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprTy *Op); - - virtual ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprTy *Op); - - virtual ExprResult ActOnInitList(SourceLocation LParenLoc, - ExprTy **InitList, unsigned NumInit, - SourceLocation RParenLoc); - - virtual ExprResult ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind, - ExprTy *LHS,ExprTy *RHS); - - /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null - /// in the case of a the GNU conditional expr extension. - virtual ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, - SourceLocation ColonLoc, - ExprTy *Cond, ExprTy *LHS, ExprTy *RHS); - - /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". - virtual ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, - IdentifierInfo *LabelII); - - virtual ExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt, - SourceLocation RPLoc); // "({..})" - - /// __builtin_offsetof(type, a.b[123][456].c) - virtual ExprResult ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, - SourceLocation TypeLoc, TypeTy *Arg1, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RParenLoc); - - // __builtin_types_compatible_p(type1, type2) - virtual ExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeTy *arg1, TypeTy *arg2, - SourceLocation RPLoc); - - // __builtin_choose_expr(constExpr, expr1, expr2) - virtual ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, - ExprTy *cond, ExprTy *expr1, ExprTy *expr2, - SourceLocation RPLoc); - - // __builtin_overload(...) - virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc); - - // __builtin_va_arg(expr, type) - virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc, - ExprTy *expr, TypeTy *type, - SourceLocation RPLoc); - - /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. - virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, TypeTy *Ty, - SourceLocation RAngleBracketLoc, - SourceLocation LParenLoc, ExprTy *E, - SourceLocation RParenLoc); - - /// ActOnCXXBoolLiteral - Parse {true,false} literals. - virtual ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, - tok::TokenKind Kind); - - //// ActOnCXXThrow - Parse throw expressions. - virtual ExprResult ActOnCXXThrow(SourceLocation OpLoc, - ExprTy *expr); - - // ParseObjCStringLiteral - Parse Objective-C string literals. - virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, - ExprTy **Strings, - unsigned NumStrings); - virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, - SourceLocation EncodeLoc, - SourceLocation LParenLoc, - TypeTy *Ty, - SourceLocation RParenLoc); - - // ParseObjCSelectorExpression - Build selector expression for @selector - virtual ExprResult ParseObjCSelectorExpression(Selector Sel, - SourceLocation AtLoc, - SourceLocation SelLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - // ParseObjCProtocolExpression - Build protocol expression for @protocol - virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - // Objective-C declarations. - virtual DeclTy *ActOnStartClassInterface( - SourceLocation AtInterafceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperName, SourceLocation SuperLoc, - IdentifierInfo **ProtocolNames, unsigned NumProtocols, - SourceLocation EndProtoLoc, AttributeList *AttrList); - - virtual DeclTy *ActOnCompatiblityAlias( - SourceLocation AtCompatibilityAliasLoc, - IdentifierInfo *AliasName, SourceLocation AliasLocation, - IdentifierInfo *ClassName, SourceLocation ClassLocation); - - virtual DeclTy *ActOnStartProtocolInterface( - SourceLocation AtProtoInterfaceLoc, - IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, - IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc); - - virtual DeclTy *ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, - IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc); - - virtual DeclTy *ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc); - - virtual DeclTy *ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - IdentifierInfo *CatName, - SourceLocation CatLoc); - - virtual DeclTy *ActOnForwardClassDeclaration(SourceLocation Loc, - IdentifierInfo **IdentList, - unsigned NumElts); - - virtual DeclTy *ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, - IdentifierInfo **IdentList, - unsigned NumElts); - - virtual void FindProtocolDeclaration(SourceLocation TypeLoc, - IdentifierInfo **ProtocolId, - unsigned NumProtocols, - llvm::SmallVector & - Protocols); - - virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, - DeclTy **allMethods = 0, unsigned allNum = 0, - DeclTy **allProperties = 0, unsigned pNum = 0); - - virtual DeclTy *ActOnAddObjCProperties(SourceLocation AtLoc, - DeclTy **allProperties, - unsigned NumProperties, - ObjCDeclSpec &DS); - - virtual DeclTy *ActOnMethodDeclaration( - SourceLocation BeginLoc, // location of the + or -. - SourceLocation EndLoc, // location of the ; or {. - tok::TokenKind MethodType, - DeclTy *ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, - Selector Sel, - // optional arguments. The number of types/arguments is obtained - // from the Sel.getNumArgs(). - ObjCDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames, - AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, - bool isVariadic = false); - - // ActOnClassMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnClassMessage( - Scope *S, - IdentifierInfo *receivingClassName, Selector Sel, - SourceLocation lbrac, SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs); - - // ActOnInstanceMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnInstanceMessage( - ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs); -private: - /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit - /// cast. If there is already an implicit cast, merge into the existing one. - void ImpCastExprToType(Expr *&Expr, QualType Type); - - // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts - // functions and arrays to their respective pointers (C99 6.3.2.1). - Expr *UsualUnaryConversions(Expr *&expr); - - // DefaultFunctionArrayConversion - converts functions and arrays - // to their respective pointers (C99 6.3.2.1). - void DefaultFunctionArrayConversion(Expr *&expr); - - // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that - // do not have a prototype. Integer promotions are performed on each - // argument, and arguments that have type float are promoted to double. - void DefaultArgumentPromotion(Expr *&Expr); - - // UsualArithmeticConversions - performs the UsualUnaryConversions on it's - // operands and then handles various conversions that are common to binary - // operators (C99 6.3.1.8). If both operands aren't arithmetic, this - // routine returns the first non-arithmetic type found. The client is - // responsible for emitting appropriate error diagnostics. - QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, - bool isCompAssign = false); - - /// AssignConvertType - All of the 'assignment' semantic checks return this - /// enum to indicate whether the assignment was allowed. These checks are - /// done for simple assignments, as well as initialization, return from - /// function, argument passing, etc. The query is phrased in terms of a - /// source and destination type. - enum AssignConvertType { - /// Compatible - the types are compatible according to the standard. - Compatible, - - /// PointerToInt - The assignment converts a pointer to an int, which we - /// accept as an extension. - PointerToInt, - - /// IntToPointer - The assignment converts an int to a pointer, which we - /// accept as an extension. - IntToPointer, - - /// FunctionVoidPointer - The assignment is between a function pointer and - /// void*, which the standard doesn't allow, but we accept as an extension. - FunctionVoidPointer, - - /// IncompatiblePointer - The assignment is between two pointers types that - /// are not compatible, but we accept them as an extension. - IncompatiblePointer, - - /// CompatiblePointerDiscardsQualifiers - The assignment discards - /// c/v/r qualifiers, which we accept as an extension. - CompatiblePointerDiscardsQualifiers, - - /// Incompatible - We reject this conversion outright, it is invalid to - /// represent it in the AST. - Incompatible - }; - - /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the - /// assignment conversion type specified by ConvTy. This returns true if the - /// conversion was invalid or false if the conversion was accepted. - bool DiagnoseAssignmentResult(AssignConvertType ConvTy, - SourceLocation Loc, - QualType DstType, QualType SrcType, - Expr *SrcExpr, const char *Flavor); - - /// CheckAssignmentConstraints - Perform type checking for assignment, - /// argument passing, variable initialization, and function return values. - /// This routine is only used by the following two methods. C99 6.5.16. - AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); - - // CheckSingleAssignmentConstraints - Currently used by ActOnCallExpr, - // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, - // this routine performs the default function/array converions. - AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, - Expr *&rExpr); - // CheckCompoundAssignmentConstraints - Type check without performing any - // conversions. For compound assignments, the "Check...Operands" methods - // perform the necessary conversions. - AssignConvertType CheckCompoundAssignmentConstraints(QualType lhs, - QualType rhs); - - // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) - AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - - /// the following "Check" methods will return a valid/converted QualType - /// or a null QualType (indicating an error diagnostic was issued). - - /// type checking binary operators (subroutines of ActOnBinOp). - inline QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); - inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); - inline QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - inline QualType CheckRemainderOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - inline QualType CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - inline QualType CheckSubtractionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - inline QualType CheckShiftOperands( // C99 6.5.7 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - inline QualType CheckCompareOperands( // C99 6.5.8/9 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isRelational); - inline QualType CheckBitwiseOperands( // C99 6.5.[10...12] - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - inline QualType CheckLogicalOperands( // C99 6.5.[13,14] - Expr *&lex, Expr *&rex, SourceLocation OpLoc); - // CheckAssignmentOperands is used for both simple and compound assignment. - // For simple assignment, pass both expressions and a null converted type. - // For compound assignment, pass both expressions and the converted type. - inline QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] - Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType); - inline QualType CheckCommaOperands( // C99 6.5.17 - Expr *&lex, Expr *&rex, SourceLocation OpLoc); - inline QualType CheckConditionalOperands( // C99 6.5.15 - Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - - /// type checking unary operators (subroutines of ActOnUnaryOp). - /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 - QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc); - QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); - QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); - QualType CheckSizeOfAlignOfOperand(QualType type, SourceLocation loc, - bool isSizeof); - QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc); - - /// type checking primary expressions. - QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc, - IdentifierInfo &Comp, SourceLocation CmpLoc); - - /// type checking declaration initializers (C99 6.7.8) - bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType); - bool CheckSingleInitializer(Expr *&simpleInit, QualType declType); - bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, - QualType ElementType); - bool CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, - bool topLevel, unsigned& startIndex); - bool CheckForConstantInitializer(Expr *e, QualType t); - - StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType); - bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT); - - // CheckVectorCast - check type constraints for vectors. - // Since vectors are an extension, there are no C standard reference for this. - // We allow casting between vectors and integer datatypes of the same size. - // returns true if the cast is invalid - bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty); - - // returns true if there were any incompatible arguments. - bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, - ObjCMethodDecl *Method); - - /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have - /// the specified width and sign. If an overflow occurs, detect it and emit - /// the specified diagnostic. - void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, - unsigned NewWidth, bool NewSign, - SourceLocation Loc, unsigned DiagID); - - void InitBuiltinVaListType(); - - //===--------------------------------------------------------------------===// - // Extra semantic analysis beyond the C type system -private: - bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); - bool CheckBuiltinCFStringArgument(Expr* Arg); - bool SemaBuiltinVAStart(CallExpr *TheCall); - bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); - void CheckPrintfArguments(CallExpr *TheCall, - bool HasVAListArg, unsigned format_idx); - void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, - SourceLocation ReturnLoc); - void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); -}; - - -} // end namespace clang - -#endif diff --git a/clang/Sema/SemaChecking.cpp b/clang/Sema/SemaChecking.cpp deleted file mode 100644 index 6d3eea5e730..00000000000 --- a/clang/Sema/SemaChecking.cpp +++ /dev/null @@ -1,802 +0,0 @@ -//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements extra semantic analysis beyond what is enforced -// by the C type system. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/LiteralSupport.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "SemaUtil.h" -using namespace clang; - -/// CheckFunctionCall - Check a direct function call for various correctness -/// and safety properties not strictly enforced by the C type system. -bool -Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { - - // Get the IdentifierInfo* for the called function. - IdentifierInfo *FnInfo = FDecl->getIdentifier(); - - switch (FnInfo->getBuiltinID()) { - case Builtin::BI__builtin___CFStringMakeConstantString: - assert(TheCall->getNumArgs() == 1 && - "Wrong # arguments to builtin CFStringMakeConstantString"); - return CheckBuiltinCFStringArgument(TheCall->getArg(0)); - case Builtin::BI__builtin_va_start: - return SemaBuiltinVAStart(TheCall); - - case Builtin::BI__builtin_isgreater: - case Builtin::BI__builtin_isgreaterequal: - case Builtin::BI__builtin_isless: - case Builtin::BI__builtin_islessequal: - case Builtin::BI__builtin_islessgreater: - case Builtin::BI__builtin_isunordered: - return SemaBuiltinUnorderedCompare(TheCall); - } - - // Search the KnownFunctionIDs for the identifier. - unsigned i = 0, e = id_num_known_functions; - for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; } - if (i == e) return false; - - // Printf checking. - if (i <= id_vprintf) { - // Retrieve the index of the format string parameter and determine - // if the function is passed a va_arg argument. - unsigned format_idx = 0; - bool HasVAListArg = false; - - switch (i) { - default: assert(false && "No format string argument index."); - case id_printf: format_idx = 0; break; - case id_fprintf: format_idx = 1; break; - case id_sprintf: format_idx = 1; break; - case id_snprintf: format_idx = 2; break; - case id_asprintf: format_idx = 1; break; - case id_vsnprintf: format_idx = 2; HasVAListArg = true; break; - case id_vasprintf: format_idx = 1; HasVAListArg = true; break; - case id_vfprintf: format_idx = 1; HasVAListArg = true; break; - case id_vsprintf: format_idx = 1; HasVAListArg = true; break; - case id_vprintf: format_idx = 0; HasVAListArg = true; break; - } - - CheckPrintfArguments(TheCall, HasVAListArg, format_idx); - } - - return false; -} - -/// CheckBuiltinCFStringArgument - Checks that the argument to the builtin -/// CFString constructor is correct -bool Sema::CheckBuiltinCFStringArgument(Expr* Arg) { - Arg = Arg->IgnoreParenCasts(); - - StringLiteral *Literal = dyn_cast(Arg); - - if (!Literal || Literal->isWide()) { - Diag(Arg->getLocStart(), - diag::err_cfstring_literal_not_string_constant, - Arg->getSourceRange()); - return true; - } - - const char *Data = Literal->getStrData(); - unsigned Length = Literal->getByteLength(); - - for (unsigned i = 0; i < Length; ++i) { - if (!isascii(Data[i])) { - Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1), - diag::warn_cfstring_literal_contains_non_ascii_character, - Arg->getSourceRange()); - break; - } - - if (!Data[i]) { - Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1), - diag::warn_cfstring_literal_contains_nul_character, - Arg->getSourceRange()); - break; - } - } - - return false; -} - -/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity. -/// Emit an error and return true on failure, return false on success. -bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { - Expr *Fn = TheCall->getCallee(); - if (TheCall->getNumArgs() > 2) { - Diag(TheCall->getArg(2)->getLocStart(), - diag::err_typecheck_call_too_many_args, Fn->getSourceRange(), - SourceRange(TheCall->getArg(2)->getLocStart(), - (*(TheCall->arg_end()-1))->getLocEnd())); - return true; - } - - // Determine whether the current function is variadic or not. - bool isVariadic; - if (CurFunctionDecl) - isVariadic = - cast(CurFunctionDecl->getType())->isVariadic(); - else - isVariadic = CurMethodDecl->isVariadic(); - - if (!isVariadic) { - Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); - return true; - } - - // Verify that the second argument to the builtin is the last argument of the - // current function or method. - bool SecondArgIsLastNamedArgument = false; - const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); - - if (const DeclRefExpr *DR = dyn_cast(Arg)) { - if (const ParmVarDecl *PV = dyn_cast(DR->getDecl())) { - // FIXME: This isn't correct for methods (results in bogus warning). - // Get the last formal in the current function. - const ParmVarDecl *LastArg; - if (CurFunctionDecl) - LastArg = *(CurFunctionDecl->param_end()-1); - else - LastArg = *(CurMethodDecl->param_end()-1); - SecondArgIsLastNamedArgument = PV == LastArg; - } - } - - if (!SecondArgIsLastNamedArgument) - Diag(TheCall->getArg(1)->getLocStart(), - diag::warn_second_parameter_of_va_start_not_last_named_argument); - return false; -} - -/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and -/// friends. This is declared to take (...), so we have to check everything. -bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { - if (TheCall->getNumArgs() < 2) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args); - if (TheCall->getNumArgs() > 2) - return Diag(TheCall->getArg(2)->getLocStart(), - diag::err_typecheck_call_too_many_args, - SourceRange(TheCall->getArg(2)->getLocStart(), - (*(TheCall->arg_end()-1))->getLocEnd())); - - Expr *OrigArg0 = TheCall->getArg(0); - Expr *OrigArg1 = TheCall->getArg(1); - - // Do standard promotions between the two arguments, returning their common - // type. - QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); - - // If the common type isn't a real floating type, then the arguments were - // invalid for this operation. - if (!Res->isRealFloatingType()) - return Diag(OrigArg0->getLocStart(), - diag::err_typecheck_call_invalid_ordered_compare, - OrigArg0->getType().getAsString(), - OrigArg1->getType().getAsString(), - SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd())); - - return false; -} - - -/// CheckPrintfArguments - Check calls to printf (and similar functions) for -/// correct use of format strings. -/// -/// HasVAListArg - A predicate indicating whether the printf-like -/// function is passed an explicit va_arg argument (e.g., vprintf) -/// -/// format_idx - The index into Args for the format string. -/// -/// Improper format strings to functions in the printf family can be -/// the source of bizarre bugs and very serious security holes. A -/// good source of information is available in the following paper -/// (which includes additional references): -/// -/// FormatGuard: Automatic Protection From printf Format String -/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001. -/// -/// Functionality implemented: -/// -/// We can statically check the following properties for string -/// literal format strings for non v.*printf functions (where the -/// arguments are passed directly): -// -/// (1) Are the number of format conversions equal to the number of -/// data arguments? -/// -/// (2) Does each format conversion correctly match the type of the -/// corresponding data argument? (TODO) -/// -/// Moreover, for all printf functions we can: -/// -/// (3) Check for a missing format string (when not caught by type checking). -/// -/// (4) Check for no-operation flags; e.g. using "#" with format -/// conversion 'c' (TODO) -/// -/// (5) Check the use of '%n', a major source of security holes. -/// -/// (6) Check for malformed format conversions that don't specify anything. -/// -/// (7) Check for empty format strings. e.g: printf(""); -/// -/// (8) Check that the format string is a wide literal. -/// -/// (9) Also check the arguments of functions with the __format__ attribute. -/// (TODO). -/// -/// All of these checks can be done by parsing the format string. -/// -/// For now, we ONLY do (1), (3), (5), (6), (7), and (8). -void -Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx) { - Expr *Fn = TheCall->getCallee(); - - // CHECK: printf-like function is called with no format string. - if (format_idx >= TheCall->getNumArgs()) { - Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string, - Fn->getSourceRange()); - return; - } - - Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts(); - - // CHECK: format string is not a string literal. - // - // Dynamically generated format strings are difficult to - // automatically vet at compile time. Requiring that format strings - // are string literals: (1) permits the checking of format strings by - // the compiler and thereby (2) can practically remove the source of - // many format string exploits. - StringLiteral *FExpr = dyn_cast(OrigFormatExpr); - if (FExpr == NULL) { - // For vprintf* functions (i.e., HasVAListArg==true), we add a - // special check to see if the format string is a function parameter - // of the function calling the printf function. If the function - // has an attribute indicating it is a printf-like function, then we - // should suppress warnings concerning non-literals being used in a call - // to a vprintf function. For example: - // - // void - // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...) { - // va_list ap; - // va_start(ap, fmt); - // vprintf(fmt, ap); // Do NOT emit a warning about "fmt". - // ... - // - // - // FIXME: We don't have full attribute support yet, so just check to see - // if the argument is a DeclRefExpr that references a parameter. We'll - // add proper support for checking the attribute later. - if (HasVAListArg) - if (DeclRefExpr* DR = dyn_cast(OrigFormatExpr)) - if (isa(DR->getDecl())) - return; - - Diag(TheCall->getArg(format_idx)->getLocStart(), - diag::warn_printf_not_string_constant, Fn->getSourceRange()); - return; - } - - // CHECK: is the format string a wide literal? - if (FExpr->isWide()) { - Diag(FExpr->getLocStart(), - diag::warn_printf_format_string_is_wide_literal, Fn->getSourceRange()); - return; - } - - // Str - The format string. NOTE: this is NOT null-terminated! - const char * const Str = FExpr->getStrData(); - - // CHECK: empty format string? - const unsigned StrLen = FExpr->getByteLength(); - - if (StrLen == 0) { - Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string, - Fn->getSourceRange()); - return; - } - - // We process the format string using a binary state machine. The - // current state is stored in CurrentState. - enum { - state_OrdChr, - state_Conversion - } CurrentState = state_OrdChr; - - // numConversions - The number of conversions seen so far. This is - // incremented as we traverse the format string. - unsigned numConversions = 0; - - // numDataArgs - The number of data arguments after the format - // string. This can only be determined for non vprintf-like - // functions. For those functions, this value is 1 (the sole - // va_arg argument). - unsigned numDataArgs = TheCall->getNumArgs()-(format_idx+1); - - // Inspect the format string. - unsigned StrIdx = 0; - - // LastConversionIdx - Index within the format string where we last saw - // a '%' character that starts a new format conversion. - unsigned LastConversionIdx = 0; - - for (; StrIdx < StrLen; ++StrIdx) { - - // Is the number of detected conversion conversions greater than - // the number of matching data arguments? If so, stop. - if (!HasVAListArg && numConversions > numDataArgs) break; - - // Handle "\0" - if (Str[StrIdx] == '\0') { - // The string returned by getStrData() is not null-terminated, - // so the presence of a null character is likely an error. - Diag(PP.AdvanceToTokenCharacter(FExpr->getLocStart(), StrIdx+1), - diag::warn_printf_format_string_contains_null_char, - Fn->getSourceRange()); - return; - } - - // Ordinary characters (not processing a format conversion). - if (CurrentState == state_OrdChr) { - if (Str[StrIdx] == '%') { - CurrentState = state_Conversion; - LastConversionIdx = StrIdx; - } - continue; - } - - // Seen '%'. Now processing a format conversion. - switch (Str[StrIdx]) { - // Handle dynamic precision or width specifier. - case '*': { - ++numConversions; - - if (!HasVAListArg && numConversions > numDataArgs) { - SourceLocation Loc = FExpr->getLocStart(); - Loc = PP.AdvanceToTokenCharacter(Loc, StrIdx+1); - - if (Str[StrIdx-1] == '.') - Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg, - Fn->getSourceRange()); - else - Diag(Loc, diag::warn_printf_asterisk_width_missing_arg, - Fn->getSourceRange()); - - // Don't do any more checking. We'll just emit spurious errors. - return; - } - - // Perform type checking on width/precision specifier. - Expr *E = TheCall->getArg(format_idx+numConversions); - if (const BuiltinType *BT = E->getType()->getAsBuiltinType()) - if (BT->getKind() == BuiltinType::Int) - break; - - SourceLocation Loc = - PP.AdvanceToTokenCharacter(FExpr->getLocStart(), StrIdx+1); - - if (Str[StrIdx-1] == '.') - Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type, - E->getType().getAsString(), E->getSourceRange()); - else - Diag(Loc, diag::warn_printf_asterisk_width_wrong_type, - E->getType().getAsString(), E->getSourceRange()); - - break; - } - - // Characters which can terminate a format conversion - // (e.g. "%d"). Characters that specify length modifiers or - // other flags are handled by the default case below. - // - // FIXME: additional checks will go into the following cases. - case 'i': - case 'd': - case 'o': - case 'u': - case 'x': - case 'X': - case 'D': - case 'O': - case 'U': - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case 'a': - case 'A': - case 'c': - case 'C': - case 'S': - case 's': - case 'p': - ++numConversions; - CurrentState = state_OrdChr; - break; - - // CHECK: Are we using "%n"? Issue a warning. - case 'n': { - ++numConversions; - CurrentState = state_OrdChr; - SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), - LastConversionIdx+1); - - Diag(Loc, diag::warn_printf_write_back, Fn->getSourceRange()); - break; - } - - // Handle "%%" - case '%': - // Sanity check: Was the first "%" character the previous one? - // If not, we will assume that we have a malformed format - // conversion, and that the current "%" character is the start - // of a new conversion. - if (StrIdx - LastConversionIdx == 1) - CurrentState = state_OrdChr; - else { - // Issue a warning: invalid format conversion. - SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), - LastConversionIdx+1); - - Diag(Loc, diag::warn_printf_invalid_conversion, - std::string(Str+LastConversionIdx, Str+StrIdx), - Fn->getSourceRange()); - - // This conversion is broken. Advance to the next format - // conversion. - LastConversionIdx = StrIdx; - ++numConversions; - } - break; - - default: - // This case catches all other characters: flags, widths, etc. - // We should eventually process those as well. - break; - } - } - - if (CurrentState == state_Conversion) { - // Issue a warning: invalid format conversion. - SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), - LastConversionIdx+1); - - Diag(Loc, diag::warn_printf_invalid_conversion, - std::string(Str+LastConversionIdx, - Str+std::min(LastConversionIdx+2, StrLen)), - Fn->getSourceRange()); - return; - } - - if (!HasVAListArg) { - // CHECK: Does the number of format conversions exceed the number - // of data arguments? - if (numConversions > numDataArgs) { - SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), - LastConversionIdx); - - Diag(Loc, diag::warn_printf_insufficient_data_args, - Fn->getSourceRange()); - } - // CHECK: Does the number of data arguments exceed the number of - // format conversions in the format string? - else if (numConversions < numDataArgs) - Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(), - diag::warn_printf_too_many_data_args, Fn->getSourceRange()); - } -} - -//===--- CHECK: Return Address of Stack Variable --------------------------===// - -static DeclRefExpr* EvalVal(Expr *E); -static DeclRefExpr* EvalAddr(Expr* E); - -/// CheckReturnStackAddr - Check if a return statement returns the address -/// of a stack variable. -void -Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, - SourceLocation ReturnLoc) { - - // Perform checking for returned stack addresses. - if (lhsType->isPointerType()) { - if (DeclRefExpr *DR = EvalAddr(RetValExp)) - Diag(DR->getLocStart(), diag::warn_ret_stack_addr, - DR->getDecl()->getIdentifier()->getName(), - RetValExp->getSourceRange()); - } - // Perform checking for stack values returned by reference. - else if (lhsType->isReferenceType()) { - // Check for an implicit cast to a reference. - if (ImplicitCastExpr *I = dyn_cast(RetValExp)) - if (DeclRefExpr *DR = EvalVal(I->getSubExpr())) - Diag(DR->getLocStart(), diag::warn_ret_stack_ref, - DR->getDecl()->getIdentifier()->getName(), - RetValExp->getSourceRange()); - } -} - -/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that -/// check if the expression in a return statement evaluates to an address -/// to a location on the stack. The recursion is used to traverse the -/// AST of the return expression, with recursion backtracking when we -/// encounter a subexpression that (1) clearly does not lead to the address -/// of a stack variable or (2) is something we cannot determine leads to -/// the address of a stack variable based on such local checking. -/// -/// EvalAddr processes expressions that are pointers that are used as -/// references (and not L-values). EvalVal handles all other values. -/// At the base case of the recursion is a check for a DeclRefExpr* in -/// the refers to a stack variable. -/// -/// This implementation handles: -/// -/// * pointer-to-pointer casts -/// * implicit conversions from array references to pointers -/// * taking the address of fields -/// * arbitrary interplay between "&" and "*" operators -/// * pointer arithmetic from an address of a stack variable -/// * taking the address of an array element where the array is on the stack -static DeclRefExpr* EvalAddr(Expr *E) { - // We should only be called for evaluating pointer expressions. - assert((E->getType()->isPointerType() || - E->getType()->isObjCQualifiedIdType()) && - "EvalAddr only works on pointers"); - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - switch (E->getStmtClass()) { - case Stmt::ParenExprClass: - // Ignore parentheses. - return EvalAddr(cast(E)->getSubExpr()); - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is AddrOf. All others don't make sense as pointers. - UnaryOperator *U = cast(E); - - if (U->getOpcode() == UnaryOperator::AddrOf) - return EvalVal(U->getSubExpr()); - else - return NULL; - } - - case Stmt::BinaryOperatorClass: { - // Handle pointer arithmetic. All other binary operators are not valid - // in this context. - BinaryOperator *B = cast(E); - BinaryOperator::Opcode op = B->getOpcode(); - - if (op != BinaryOperator::Add && op != BinaryOperator::Sub) - return NULL; - - Expr *Base = B->getLHS(); - - // Determine which argument is the real pointer base. It could be - // the RHS argument instead of the LHS. - if (!Base->getType()->isPointerType()) Base = B->getRHS(); - - assert (Base->getType()->isPointerType()); - return EvalAddr(Base); - } - - // For conditional operators we need to see if either the LHS or RHS are - // valid DeclRefExpr*s. If one of them is valid, we return it. - case Stmt::ConditionalOperatorClass: { - ConditionalOperator *C = cast(E); - - // Handle the GNU extension for missing LHS. - if (Expr *lhsExpr = C->getLHS()) - if (DeclRefExpr* LHS = EvalAddr(lhsExpr)) - return LHS; - - return EvalAddr(C->getRHS()); - } - - // For implicit casts, we need to handle conversions from arrays to - // pointer values, and implicit pointer-to-pointer conversions. - case Stmt::ImplicitCastExprClass: { - ImplicitCastExpr *IE = cast(E); - Expr* SubExpr = IE->getSubExpr(); - - if (SubExpr->getType()->isPointerType() || - SubExpr->getType()->isObjCQualifiedIdType()) - return EvalAddr(SubExpr); - else - return EvalVal(SubExpr); - } - - // For casts, we handle pointer-to-pointer conversions (which - // is essentially a no-op from our mini-interpreter's standpoint). - // For other casts we abort. - case Stmt::CastExprClass: { - CastExpr *C = cast(E); - Expr *SubExpr = C->getSubExpr(); - - if (SubExpr->getType()->isPointerType()) - return EvalAddr(SubExpr); - else - return NULL; - } - - // C++ casts. For dynamic casts, static casts, and const casts, we - // are always converting from a pointer-to-pointer, so we just blow - // through the cast. In the case the dynamic cast doesn't fail - // (and return NULL), we take the conservative route and report cases - // where we return the address of a stack variable. For Reinterpre - case Stmt::CXXCastExprClass: { - CXXCastExpr *C = cast(E); - - if (C->getOpcode() == CXXCastExpr::ReinterpretCast) { - Expr *S = C->getSubExpr(); - if (S->getType()->isPointerType()) - return EvalAddr(S); - else - return NULL; - } - else - return EvalAddr(C->getSubExpr()); - } - - // Everything else: we simply don't reason about them. - default: - return NULL; - } -} - - -/// EvalVal - This function is complements EvalAddr in the mutual recursion. -/// See the comments for EvalAddr for more details. -static DeclRefExpr* EvalVal(Expr *E) { - - // We should only be called for evaluating non-pointer expressions, or - // expressions with a pointer type that are not used as references but instead - // are l-values (e.g., DeclRefExpr with a pointer type). - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: { - // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking - // at code that refers to a variable's name. We check if it has local - // storage within the function, and if so, return the expression. - DeclRefExpr *DR = cast(E); - - if (VarDecl *V = dyn_cast(DR->getDecl())) - if(V->hasLocalStorage()) return DR; - - return NULL; - } - - case Stmt::ParenExprClass: - // Ignore parentheses. - return EvalVal(cast(E)->getSubExpr()); - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - UnaryOperator *U = cast(E); - - if (U->getOpcode() == UnaryOperator::Deref) - return EvalAddr(U->getSubExpr()); - - return NULL; - } - - case Stmt::ArraySubscriptExprClass: { - // Array subscripts are potential references to data on the stack. We - // retrieve the DeclRefExpr* for the array variable if it indeed - // has local storage. - return EvalAddr(cast(E)->getBase()); - } - - case Stmt::ConditionalOperatorClass: { - // For conditional operators we need to see if either the LHS or RHS are - // non-NULL DeclRefExpr's. If one is non-NULL, we return it. - ConditionalOperator *C = cast(E); - - // Handle the GNU extension for missing LHS. - if (Expr *lhsExpr = C->getLHS()) - if (DeclRefExpr *LHS = EvalVal(lhsExpr)) - return LHS; - - return EvalVal(C->getRHS()); - } - - // Accesses to members are potential references to data on the stack. - case Stmt::MemberExprClass: { - MemberExpr *M = cast(E); - - // Check for indirect access. We only want direct field accesses. - if (!M->isArrow()) - return EvalVal(M->getBase()); - else - return NULL; - } - - // Everything else: we simply don't reason about them. - default: - return NULL; - } -} - -//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// - -/// Check for comparisons of floating point operands using != and ==. -/// Issue a warning if these are no self-comparisons, as they are not likely -/// to do what the programmer intended. -void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { - bool EmitWarning = true; - - Expr* LeftExprSansParen = lex->IgnoreParens(); - Expr* RightExprSansParen = rex->IgnoreParens(); - - // Special case: check for x == x (which is OK). - // Do not emit warnings for such cases. - if (DeclRefExpr* DRL = dyn_cast(LeftExprSansParen)) - if (DeclRefExpr* DRR = dyn_cast(RightExprSansParen)) - if (DRL->getDecl() == DRR->getDecl()) - EmitWarning = false; - - - // Special case: check for comparisons against literals that can be exactly - // represented by APFloat. In such cases, do not emit a warning. This - // is a heuristic: often comparison against such literals are used to - // detect if a value in a variable has not changed. This clearly can - // lead to false negatives. - if (EmitWarning) { - if (FloatingLiteral* FLL = dyn_cast(LeftExprSansParen)) { - if (FLL->isExact()) - EmitWarning = false; - } - else - if (FloatingLiteral* FLR = dyn_cast(RightExprSansParen)){ - if (FLR->isExact()) - EmitWarning = false; - } - } - - // Check for comparisons with builtin types. - if (EmitWarning) - if (CallExpr* CL = dyn_cast(LeftExprSansParen)) - if (isCallBuiltin(CL)) - EmitWarning = false; - - if (EmitWarning) - if (CallExpr* CR = dyn_cast(RightExprSansParen)) - if (isCallBuiltin(CR)) - EmitWarning = false; - - // Emit the diagnostic. - if (EmitWarning) - Diag(loc, diag::warn_floatingpoint_eq, - lex->getSourceRange(),rex->getSourceRange()); -} diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp deleted file mode 100644 index 7914e865741..00000000000 --- a/clang/Sema/SemaDecl.cpp +++ /dev/null @@ -1,2297 +0,0 @@ -//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for declarations. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/AST/Builtins.h" -#include "clang/AST/Decl.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Type.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/SourceManager.h" -// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/DenseSet.h" -using namespace clang; - -Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const { - Decl *IIDecl = II.getFETokenInfo(); - // Find first occurance of none-tagged declaration - while(IIDecl && IIDecl->getIdentifierNamespace() != Decl::IDNS_Ordinary) - IIDecl = cast(IIDecl)->getNext(); - if (!IIDecl) - return 0; - if (isa(IIDecl) || isa(IIDecl)) - return IIDecl; - if (ObjCCompatibleAliasDecl *ADecl = - dyn_cast(IIDecl)) - return ADecl->getClassInterface(); - return 0; -} - -void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { - if (S->decl_empty()) return; - assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!"); - - for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); - I != E; ++I) { - Decl *TmpD = static_cast(*I); - assert(TmpD && "This decl didn't get pushed??"); - ScopedDecl *D = dyn_cast(TmpD); - assert(D && "This decl isn't a ScopedDecl?"); - - IdentifierInfo *II = D->getIdentifier(); - if (!II) continue; - - // Unlink this decl from the identifier. Because the scope contains decls - // in an unordered collection, and because we have multiple identifier - // namespaces (e.g. tag, normal, label),the decl may not be the first entry. - if (II->getFETokenInfo() == D) { - // Normal case, no multiple decls in different namespaces. - II->setFETokenInfo(D->getNext()); - } else { - // Scan ahead. There are only three namespaces in C, so this loop can - // never execute more than 3 times. - ScopedDecl *SomeDecl = II->getFETokenInfo(); - while (SomeDecl->getNext() != D) { - SomeDecl = SomeDecl->getNext(); - assert(SomeDecl && "Didn't find this decl on its identifier's chain!"); - } - SomeDecl->setNext(D->getNext()); - } - - // This will have to be revisited for C++: there we want to nest stuff in - // namespace decls etc. Even for C, we might want a top-level translation - // unit decl or something. - if (!CurFunctionDecl) - continue; - - // Chain this decl to the containing function, it now owns the memory for - // the decl. - D->setNext(CurFunctionDecl->getDeclChain()); - CurFunctionDecl->setDeclChain(D); - } -} - -/// LookupInterfaceDecl - Lookup interface declaration in the scope chain. -/// Return the first declaration found (which may or may not be a class -/// declaration. Caller is responsible for handling the none-class case. -/// Bypassing the alias of a class by returning the aliased class. -ScopedDecl *Sema::LookupInterfaceDecl(IdentifierInfo *ClassName) { - ScopedDecl *IDecl; - // Scan up the scope chain looking for a decl that matches this identifier - // that is in the appropriate namespace. - for (IDecl = ClassName->getFETokenInfo(); IDecl; - IDecl = IDecl->getNext()) - if (IDecl->getIdentifierNamespace() == Decl::IDNS_Ordinary) - break; - - if (ObjCCompatibleAliasDecl *ADecl = - dyn_cast_or_null(IDecl)) - return ADecl->getClassInterface(); - return IDecl; -} - -/// getObjCInterfaceDecl - Look up a for a class declaration in the scope. -/// return 0 if one not found. -ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { - ScopedDecl *IdDecl = LookupInterfaceDecl(Id); - return cast_or_null(IdDecl); -} - -/// LookupScopedDecl - Look up the inner-most declaration in the specified -/// namespace. -ScopedDecl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI, - SourceLocation IdLoc, Scope *S) { - if (II == 0) return 0; - Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI; - - // Scan up the scope chain looking for a decl that matches this identifier - // that is in the appropriate namespace. This search should not take long, as - // shadowing of names is uncommon, and deep shadowing is extremely uncommon. - for (ScopedDecl *D = II->getFETokenInfo(); D; D = D->getNext()) - if (D->getIdentifierNamespace() == NS) - return D; - - // If we didn't find a use of this identifier, and if the identifier - // corresponds to a compiler builtin, create the decl object for the builtin - // now, injecting it into translation unit scope, and return it. - if (NS == Decl::IDNS_Ordinary) { - // If this is a builtin on this (or all) targets, create the decl. - if (unsigned BuiltinID = II->getBuiltinID()) - return LazilyCreateBuiltin(II, BuiltinID, S); - } - return 0; -} - -void Sema::InitBuiltinVaListType() -{ - if (!Context.getBuiltinVaListType().isNull()) - return; - - IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary, - SourceLocation(), TUScope); - TypedefDecl *VaTypedef = cast(VaDecl); - Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); -} - -/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope. -/// lazily create a decl for it. -ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, - Scope *S) { - Builtin::ID BID = (Builtin::ID)bid; - - if (BID == Builtin::BI__builtin_va_start || - BID == Builtin::BI__builtin_va_copy || - BID == Builtin::BI__builtin_va_end) - InitBuiltinVaListType(); - - QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context); - FunctionDecl *New = FunctionDecl::Create(Context, SourceLocation(), II, R, - FunctionDecl::Extern, false, 0); - - // Find translation-unit scope to insert this function into. - if (Scope *FnS = S->getFnParent()) - S = FnS->getParent(); // Skip all scopes in a function at once. - while (S->getParent()) - S = S->getParent(); - S->AddDecl(New); - - // Add this decl to the end of the identifier info. - if (ScopedDecl *LastDecl = II->getFETokenInfo()) { - // Scan until we find the last (outermost) decl in the id chain. - while (LastDecl->getNext()) - LastDecl = LastDecl->getNext(); - // Insert before (outside) it. - LastDecl->setNext(New); - } else { - II->setFETokenInfo(New); - } - return New; -} - -/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. -/// -TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) { - // Verify the old decl was also a typedef. - TypedefDecl *Old = dyn_cast(OldD); - if (!Old) { - Diag(New->getLocation(), diag::err_redefinition_different_kind, - New->getName()); - Diag(OldD->getLocation(), diag::err_previous_definition); - return New; - } - - // Allow multiple definitions for ObjC built-in typedefs. - // FIXME: Verify the underlying types are equivalent! - if (getLangOptions().ObjC1 && isBuiltinObjCType(New)) - return Old; - - // Redeclaration of a type is a constraint violation (6.7.2.3p1). - // Apparently GCC, Intel, and Sun all silently ignore the redeclaration if - // *either* declaration is in a system header. The code below implements - // this adhoc compatibility rule. FIXME: The following code will not - // work properly when compiling ".i" files (containing preprocessed output). - SourceManager &SrcMgr = Context.getSourceManager(); - const FileEntry *OldDeclFile = SrcMgr.getFileEntryForLoc(Old->getLocation()); - const FileEntry *NewDeclFile = SrcMgr.getFileEntryForLoc(New->getLocation()); - HeaderSearch &HdrInfo = PP.getHeaderSearchInfo(); - DirectoryLookup::DirType OldDirType = HdrInfo.getFileDirFlavor(OldDeclFile); - DirectoryLookup::DirType NewDirType = HdrInfo.getFileDirFlavor(NewDeclFile); - - if ((OldDirType == DirectoryLookup::ExternCSystemHeaderDir || - NewDirType == DirectoryLookup::ExternCSystemHeaderDir) || - getLangOptions().Microsoft) - return New; - - // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. - // TODO: This is totally simplistic. It should handle merging functions - // together etc, merging extern int X; int X; ... - Diag(New->getLocation(), diag::err_redefinition, New->getName()); - Diag(Old->getLocation(), diag::err_previous_definition); - return New; -} - -/// DeclhasAttr - returns true if decl Declaration already has the target attribute. -static bool DeclHasAttr(const Decl *decl, const Attr *target) { - for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext()) - if (attr->getKind() == target->getKind()) - return true; - - return false; -} - -/// MergeAttributes - append attributes from the Old decl to the New one. -static void MergeAttributes(Decl *New, Decl *Old) { - Attr *attr = const_cast(Old->getAttrs()), *tmp; - -// FIXME: fix this code to cleanup the Old attrs correctly - while (attr) { - tmp = attr; - attr = attr->getNext(); - - if (!DeclHasAttr(New, tmp)) { - New->addAttr(tmp); - } else { - tmp->setNext(0); - delete(tmp); - } - } -} - -/// MergeFunctionDecl - We just parsed a function 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. -/// -FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, ScopedDecl *OldD) { - // Verify the old decl was also a function. - FunctionDecl *Old = dyn_cast(OldD); - if (!Old) { - Diag(New->getLocation(), diag::err_redefinition_different_kind, - New->getName()); - Diag(OldD->getLocation(), diag::err_previous_definition); - return New; - } - - MergeAttributes(New, Old); - - - QualType OldQType = Old->getCanonicalType(); - QualType NewQType = New->getCanonicalType(); - - // Function types need to be compatible, not identical. This handles - // duplicate function decls like "void f(int); void f(enum X);" properly. - if (Context.functionTypesAreCompatible(OldQType, NewQType)) - return New; - - // A function that has already been declared has been redeclared or defined - // with a different type- show appropriate diagnostic - diag::kind PrevDiag = Old->getBody() ? diag::err_previous_definition : - diag::err_previous_declaration; - - // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. - // TODO: This is totally simplistic. It should handle merging functions - // together etc, merging extern int X; int X; ... - Diag(New->getLocation(), diag::err_conflicting_types, New->getName()); - Diag(Old->getLocation(), PrevDiag); - return New; -} - -/// equivalentArrayTypes - Used to determine whether two array types are -/// equivalent. -/// We need to check this explicitly as an incomplete array definition is -/// considered a VariableArrayType, so will not match a complete array -/// definition that would be otherwise equivalent. -static bool areEquivalentArrayTypes(QualType NewQType, QualType OldQType) { - const ArrayType *NewAT = NewQType->getAsArrayType(); - const ArrayType *OldAT = OldQType->getAsArrayType(); - - if (!NewAT || !OldAT) - return false; - - // If either (or both) array types in incomplete we need to strip off the - // outer VariableArrayType. Once the outer VAT is removed the remaining - // types must be identical if the array types are to be considered - // equivalent. - // eg. int[][1] and int[1][1] become - // VAT(null, CAT(1, int)) and CAT(1, CAT(1, int)) - // removing the outermost VAT gives - // CAT(1, int) and CAT(1, int) - // which are equal, therefore the array types are equivalent. - if (NewAT->isIncompleteArrayType() || OldAT->isIncompleteArrayType()) { - if (NewAT->getIndexTypeQualifier() != OldAT->getIndexTypeQualifier()) - return false; - NewQType = NewAT->getElementType().getCanonicalType(); - OldQType = OldAT->getElementType().getCanonicalType(); - } - - return NewQType == OldQType; -} - -/// MergeVarDecl - We just parsed a variable 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. -/// -/// FIXME: Need to carefully consider tentative definition rules (C99 6.9.2p2). -/// For example, we incorrectly complain about i1, i4 from C99 6.9.2p4. -/// -VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) { - // Verify the old decl was also a variable. - VarDecl *Old = dyn_cast(OldD); - if (!Old) { - Diag(New->getLocation(), diag::err_redefinition_different_kind, - New->getName()); - Diag(OldD->getLocation(), diag::err_previous_definition); - return New; - } - - MergeAttributes(New, Old); - - // Verify the types match. - if (Old->getCanonicalType() != New->getCanonicalType() && - !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) { - Diag(New->getLocation(), diag::err_redefinition, New->getName()); - Diag(Old->getLocation(), diag::err_previous_definition); - return New; - } - // C99 6.2.2p4: Check if we have a static decl followed by a non-static. - if (New->getStorageClass() == VarDecl::Static && - (Old->getStorageClass() == VarDecl::None || - Old->getStorageClass() == VarDecl::Extern)) { - Diag(New->getLocation(), diag::err_static_non_static, New->getName()); - Diag(Old->getLocation(), diag::err_previous_definition); - return New; - } - // C99 6.2.2p4: Check if we have a non-static decl followed by a static. - if (New->getStorageClass() != VarDecl::Static && - Old->getStorageClass() == VarDecl::Static) { - Diag(New->getLocation(), diag::err_non_static_static, New->getName()); - Diag(Old->getLocation(), diag::err_previous_definition); - return New; - } - // We've verified the types match, now handle "tentative" definitions. - FileVarDecl *OldFSDecl = dyn_cast(Old); - FileVarDecl *NewFSDecl = dyn_cast(New); - - if (OldFSDecl && NewFSDecl) { - // Handle C "tentative" external object definitions (C99 6.9.2). - bool OldIsTentative = false; - bool NewIsTentative = false; - - if (!OldFSDecl->getInit() && - (OldFSDecl->getStorageClass() == VarDecl::None || - OldFSDecl->getStorageClass() == VarDecl::Static)) - OldIsTentative = true; - - // FIXME: this check doesn't work (since the initializer hasn't been - // attached yet). This check should be moved to FinalizeDeclaratorGroup. - // Unfortunately, by the time we get to FinializeDeclaratorGroup, we've - // thrown out the old decl. - if (!NewFSDecl->getInit() && - (NewFSDecl->getStorageClass() == VarDecl::None || - NewFSDecl->getStorageClass() == VarDecl::Static)) - ; // change to NewIsTentative = true; once the code is moved. - - if (NewIsTentative || OldIsTentative) - return New; - } - if (Old->getStorageClass() != VarDecl::Extern && - New->getStorageClass() != VarDecl::Extern) { - Diag(New->getLocation(), diag::err_redefinition, New->getName()); - Diag(Old->getLocation(), diag::err_previous_definition); - } - return New; -} - -/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with -/// no declarator (e.g. "struct foo;") is parsed. -Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { - // TODO: emit error on 'int;' or 'const enum foo;'. - // TODO: emit error on 'typedef int;' - // if (!DS.isMissingDeclaratorOk()) Diag(...); - - return dyn_cast_or_null(static_cast(DS.getTypeRep())); -} - -bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) { - // Get the type before calling CheckSingleAssignmentConstraints(), since - // it can promote the expression. - QualType InitType = Init->getType(); - - AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init); - return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, - InitType, Init, "initializing"); -} - -bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, - QualType ElementType) { - Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. - if (CheckSingleInitializer(expr, ElementType)) - return true; // types weren't compatible. - - if (savExpr != expr) // The type was promoted, update initializer list. - IList->setInit(slot, expr); - return false; -} - -bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { - if (const IncompleteArrayType *IAT = DeclT->getAsIncompleteArrayType()) { - // C99 6.7.8p14. We have an array of character type with unknown size - // being initialized to a string literal. - llvm::APSInt ConstVal(32); - ConstVal = strLiteral->getByteLength() + 1; - // Return a new array type (C99 6.7.8p22). - DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal, - ArrayType::Normal, 0); - } else if (const ConstantArrayType *CAT = DeclT->getAsConstantArrayType()) { - // C99 6.7.8p14. We have an array of character type with known size. - if (strLiteral->getByteLength() > (unsigned)CAT->getMaximumElements()) - Diag(strLiteral->getSourceRange().getBegin(), - diag::warn_initializer_string_for_char_array_too_long, - strLiteral->getSourceRange()); - } else { - assert(0 && "HandleStringLiteralInit(): Invalid array type"); - } - // Set type from "char *" to "constant array of char". - strLiteral->setType(DeclT); - // For now, we always return false (meaning success). - return false; -} - -StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) { - const ArrayType *AT = DeclType->getAsArrayType(); - if (AT && AT->getElementType()->isCharType()) { - return dyn_cast(Init); - } - return 0; -} - -// CheckInitializerListTypes - Checks the types of elements of an initializer -// list. This function is recursive: it calls itself to initialize subelements -// of aggregate types. Note that the topLevel parameter essentially refers to -// whether this expression "owns" the initializer list passed in, or if this -// initialization is taking elements out of a parent initializer. Each -// call to this function adds zero or more to startIndex, reports any errors, -// and returns true if it found any inconsistent types. -bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, - bool topLevel, unsigned& startIndex) { - bool hadError = false; - - if (DeclType->isScalarType()) { - // The simplest case: initializing a single scalar - if (topLevel) { - Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init, - IList->getSourceRange()); - } - if (startIndex < IList->getNumInits()) { - Expr* expr = IList->getInit(startIndex); - if (InitListExpr *SubInitList = dyn_cast(expr)) { - // FIXME: Should an error be reported here instead? - unsigned newIndex = 0; - CheckInitializerListTypes(SubInitList, DeclType, true, newIndex); - } else { - hadError |= CheckInitExpr(expr, IList, startIndex, DeclType); - } - ++startIndex; - } - // FIXME: Should an error be reported for empty initializer list + scalar? - } else if (DeclType->isVectorType()) { - if (startIndex < IList->getNumInits()) { - const VectorType *VT = DeclType->getAsVectorType(); - int maxElements = VT->getNumElements(); - QualType elementType = VT->getElementType(); - - for (int i = 0; i < maxElements; ++i) { - // Don't attempt to go past the end of the init list - if (startIndex >= IList->getNumInits()) - break; - Expr* expr = IList->getInit(startIndex); - if (InitListExpr *SubInitList = dyn_cast(expr)) { - unsigned newIndex = 0; - hadError |= CheckInitializerListTypes(SubInitList, elementType, - true, newIndex); - ++startIndex; - } else { - hadError |= CheckInitializerListTypes(IList, elementType, - false, startIndex); - } - } - } - } else if (DeclType->isAggregateType() || DeclType->isUnionType()) { - if (DeclType->isStructureType() || DeclType->isUnionType()) { - if (startIndex < IList->getNumInits() && !topLevel && - Context.typesAreCompatible(IList->getInit(startIndex)->getType(), - DeclType)) { - // We found a compatible struct; per the standard, this initializes the - // struct. (The C standard technically says that this only applies for - // initializers for declarations with automatic scope; however, this - // construct is unambiguous anyway because a struct cannot contain - // a type compatible with itself. We'll output an error when we check - // if the initializer is constant.) - // FIXME: Is a call to CheckSingleInitializer required here? - ++startIndex; - } else { - RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); - - // If the record is invalid, some of it's members are invalid. To avoid - // confusion, we forgo checking the intializer for the entire record. - if (structDecl->isInvalidDecl()) - return true; - - // If structDecl is a forward declaration, this loop won't do anything; - // That's okay, because an error should get printed out elsewhere. It - // might be worthwhile to skip over the rest of the initializer, though. - int numMembers = structDecl->getNumMembers() - - structDecl->hasFlexibleArrayMember(); - for (int i = 0; i < numMembers; i++) { - // Don't attempt to go past the end of the init list - if (startIndex >= IList->getNumInits()) - break; - FieldDecl * curField = structDecl->getMember(i); - if (!curField->getIdentifier()) { - // Don't initialize unnamed fields, e.g. "int : 20;" - continue; - } - QualType fieldType = curField->getType(); - Expr* expr = IList->getInit(startIndex); - if (InitListExpr *SubInitList = dyn_cast(expr)) { - unsigned newStart = 0; - hadError |= CheckInitializerListTypes(SubInitList, fieldType, - true, newStart); - ++startIndex; - } else { - hadError |= CheckInitializerListTypes(IList, fieldType, - false, startIndex); - } - if (DeclType->isUnionType()) - break; - } - // FIXME: Implement flexible array initialization GCC extension (it's a - // really messy extension to implement, unfortunately...the necessary - // information isn't actually even here!) - } - } else if (DeclType->isArrayType()) { - // Check for the special-case of initializing an array with a string. - if (startIndex < IList->getNumInits()) { - if (StringLiteral *lit = IsStringLiteralInit(IList->getInit(startIndex), - DeclType)) { - CheckStringLiteralInit(lit, DeclType); - ++startIndex; - if (topLevel && startIndex < IList->getNumInits()) { - // We have leftover initializers; warn - Diag(IList->getInit(startIndex)->getLocStart(), - diag::err_excess_initializers_in_char_array_initializer, - IList->getInit(startIndex)->getSourceRange()); - } - return false; - } - } - int maxElements; - if (DeclType->isIncompleteArrayType()) { - // FIXME: use a proper constant - maxElements = 0x7FFFFFFF; - } else if (const VariableArrayType *VAT = - DeclType->getAsVariableArrayType()) { - // Check for VLAs; in standard C it would be possible to check this - // earlier, but I don't know where clang accepts VLAs (gcc accepts - // them in all sorts of strange places). - Diag(VAT->getSizeExpr()->getLocStart(), - diag::err_variable_object_no_init, - VAT->getSizeExpr()->getSourceRange()); - hadError = true; - maxElements = 0x7FFFFFFF; - } else { - const ConstantArrayType *CAT = DeclType->getAsConstantArrayType(); - maxElements = static_cast(CAT->getSize().getZExtValue()); - } - QualType elementType = DeclType->getAsArrayType()->getElementType(); - int numElements = 0; - for (int i = 0; i < maxElements; ++i, ++numElements) { - // Don't attempt to go past the end of the init list - if (startIndex >= IList->getNumInits()) - break; - Expr* expr = IList->getInit(startIndex); - if (InitListExpr *SubInitList = dyn_cast(expr)) { - unsigned newIndex = 0; - hadError |= CheckInitializerListTypes(SubInitList, elementType, - true, newIndex); - ++startIndex; - } else { - hadError |= CheckInitializerListTypes(IList, elementType, - false, startIndex); - } - } - if (DeclType->isIncompleteArrayType()) { - // If this is an incomplete array type, the actual type needs to - // be calculated here - if (numElements == 0) { - // Sizing an array implicitly to zero is not allowed - // (It could in theory be allowed, but it doesn't really matter.) - Diag(IList->getLocStart(), - diag::err_at_least_one_initializer_needed_to_size_array); - hadError = true; - } else { - llvm::APSInt ConstVal(32); - ConstVal = numElements; - DeclType = Context.getConstantArrayType(elementType, ConstVal, - ArrayType::Normal, 0); - } - } - } else { - assert(0 && "Aggregate that isn't a function or array?!"); - } - } else { - // In C, all types are either scalars or aggregates, but - // additional handling is needed here for C++ (and possibly others?). - assert(0 && "Unsupported initializer type"); - } - - // If this init list is a base list, we set the type; an initializer doesn't - // fundamentally have a type, but this makes the ASTs a bit easier to read - if (topLevel) - IList->setType(DeclType); - - if (topLevel && startIndex < IList->getNumInits()) { - // We have leftover initializers; warn - Diag(IList->getInit(startIndex)->getLocStart(), - diag::warn_excess_initializers, - IList->getInit(startIndex)->getSourceRange()); - } - return hadError; -} - -bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { - // C99 6.7.8p3: The type of the entity to be initialized shall be an array - // of unknown size ("[]") or an object type that is not a variable array type. - if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) - return Diag(VAT->getSizeExpr()->getLocStart(), - diag::err_variable_object_no_init, - VAT->getSizeExpr()->getSourceRange()); - - InitListExpr *InitList = dyn_cast(Init); - if (!InitList) { - // FIXME: Handle wide strings - if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType)) - return CheckStringLiteralInit(strLiteral, DeclType); - - if (DeclType->isArrayType()) - return Diag(Init->getLocStart(), - diag::err_array_init_list_required, - Init->getSourceRange()); - - return CheckSingleInitializer(Init, DeclType); - } - unsigned newIndex = 0; - return CheckInitializerListTypes(InitList, DeclType, true, newIndex); -} - -Sema::DeclTy * -Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { - ScopedDecl *LastDeclarator = dyn_cast_or_null((Decl *)lastDecl); - IdentifierInfo *II = D.getIdentifier(); - - // All of these full declarators require an identifier. If it doesn't have - // one, the ParsedFreeStandingDeclSpec action should be used. - if (II == 0) { - Diag(D.getDeclSpec().getSourceRange().getBegin(), - diag::err_declarator_need_ident, - D.getDeclSpec().getSourceRange(), D.getSourceRange()); - return 0; - } - - // The scope passed in may not be a decl scope. Zip up the scope tree until - // we find one that is. - while ((S->getFlags() & Scope::DeclScope) == 0) - S = S->getParent(); - - // See if this is a redefinition of a variable in the same scope. - ScopedDecl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary, - D.getIdentifierLoc(), S); - ScopedDecl *New; - bool InvalidDecl = false; - - QualType R = GetTypeForDeclarator(D, S); - assert(!R.isNull() && "GetTypeForDeclarator() returned null type"); - - if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator); - if (!NewTD) return 0; - - // Handle attributes prior to checking for duplicates in MergeVarDecl - HandleDeclAttributes(NewTD, D.getDeclSpec().getAttributes(), - D.getAttributes()); - // Merge the decl with the existing one if appropriate. If the decl is - // in an outer scope, it isn't the same thing. - if (PrevDecl && S->isDeclScope(PrevDecl)) { - NewTD = MergeTypeDefDecl(NewTD, PrevDecl); - if (NewTD == 0) return 0; - } - New = NewTD; - if (S->getParent() == 0) { - // C99 6.7.7p2: If a typedef name specifies a variably modified type - // then it shall have block scope. - if (NewTD->getUnderlyingType()->isVariablyModifiedType()) { - // FIXME: Diagnostic needs to be fixed. - Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla); - InvalidDecl = true; - } - } - } else if (R.getTypePtr()->isFunctionType()) { - FunctionDecl::StorageClass SC = FunctionDecl::None; - switch (D.getDeclSpec().getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); - case DeclSpec::SCS_auto: - case DeclSpec::SCS_register: - Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func, - R.getAsString()); - InvalidDecl = true; - break; - case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break; - case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break; - case DeclSpec::SCS_static: SC = FunctionDecl::Static; break; - case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break; - } - - bool isInline = D.getDeclSpec().isInlineSpecified(); - FunctionDecl *NewFD = FunctionDecl::Create(Context, D.getIdentifierLoc(), - II, R, SC, isInline, - LastDeclarator); - // Handle attributes. - HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(), - D.getAttributes()); - - // Merge the decl with the existing one if appropriate. Since C functions - // are in a flat namespace, make sure we consider decls in outer scopes. - if (PrevDecl) { - NewFD = MergeFunctionDecl(NewFD, PrevDecl); - if (NewFD == 0) return 0; - } - New = NewFD; - } else { - if (R.getTypePtr()->isObjCInterfaceType()) { - Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object, - D.getIdentifier()->getName()); - InvalidDecl = true; - } - - VarDecl *NewVD; - VarDecl::StorageClass SC; - switch (D.getDeclSpec().getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); - case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; - case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; - case DeclSpec::SCS_static: SC = VarDecl::Static; break; - case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; - case DeclSpec::SCS_register: SC = VarDecl::Register; break; - case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; - } - if (S->getParent() == 0) { - // C99 6.9p2: The storage-class specifiers auto and register shall not - // appear in the declaration specifiers in an external declaration. - if (SC == VarDecl::Auto || SC == VarDecl::Register) { - Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope, - R.getAsString()); - InvalidDecl = true; - } - NewVD = FileVarDecl::Create(Context, D.getIdentifierLoc(), II, R, SC, - LastDeclarator); - } else { - NewVD = BlockVarDecl::Create(Context, D.getIdentifierLoc(), II, R, SC, - LastDeclarator); - } - // Handle attributes prior to checking for duplicates in MergeVarDecl - HandleDeclAttributes(NewVD, D.getDeclSpec().getAttributes(), - D.getAttributes()); - - // Emit an error if an address space was applied to decl with local storage. - // This includes arrays of objects with address space qualifiers, but not - // automatic variables that point to other address spaces. - // ISO/IEC TR 18037 S5.1.2 - if (NewVD->hasLocalStorage()) { - QualType AutoTy = NewVD->getCanonicalType(); - if (const ArrayType *AT = AutoTy->getAsArrayType()) - AutoTy = AT->getElementType().getCanonicalType(); - if (AutoTy.getAddressSpace() != 0) { - Diag(D.getIdentifierLoc(), diag::err_as_qualified_auto_decl); - InvalidDecl = true; - } - } - // Merge the decl with the existing one if appropriate. If the decl is - // in an outer scope, it isn't the same thing. - if (PrevDecl && S->isDeclScope(PrevDecl)) { - NewVD = MergeVarDecl(NewVD, PrevDecl); - if (NewVD == 0) return 0; - } - New = NewVD; - } - - // If this has an identifier, add it to the scope stack. - if (II) { - New->setNext(II->getFETokenInfo()); - II->setFETokenInfo(New); - S->AddDecl(New); - } - // If any semantic error occurred, mark the decl as invalid. - if (D.getInvalidType() || InvalidDecl) - New->setInvalidDecl(); - - return New; -} - -bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { - SourceLocation loc; - // FIXME: Remove the isReference check and handle assignment to a reference. - if (!DclT->isReferenceType() && !Init->isConstantExpr(Context, &loc)) { - assert(loc.isValid() && "isConstantExpr didn't return a loc!"); - Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange()); - return true; - } - return false; -} - -void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { - Decl *RealDecl = static_cast(dcl); - Expr *Init = static_cast(init); - assert(Init && "missing initializer"); - - // If there is no declaration, there was an error parsing it. Just ignore - // the initializer. - if (RealDecl == 0) { - delete Init; - return; - } - - VarDecl *VDecl = dyn_cast(RealDecl); - if (!VDecl) { - Diag(dyn_cast(RealDecl)->getLocation(), - diag::err_illegal_initializer); - RealDecl->setInvalidDecl(); - return; - } - // Get the decls type and save a reference for later, since - // CheckInitializerTypes may change it. - QualType DclT = VDecl->getType(), SavT = DclT; - if (BlockVarDecl *BVD = dyn_cast(VDecl)) { - VarDecl::StorageClass SC = BVD->getStorageClass(); - if (SC == VarDecl::Extern) { // C99 6.7.8p5 - Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); - BVD->setInvalidDecl(); - } else if (!BVD->isInvalidDecl()) { - if (CheckInitializerTypes(Init, DclT)) - BVD->setInvalidDecl(); - if (SC == VarDecl::Static) // C99 6.7.8p4. - CheckForConstantInitializer(Init, DclT); - } - } else if (FileVarDecl *FVD = dyn_cast(VDecl)) { - if (FVD->getStorageClass() == VarDecl::Extern) - Diag(VDecl->getLocation(), diag::warn_extern_init); - if (!FVD->isInvalidDecl()) - if (CheckInitializerTypes(Init, DclT)) - FVD->setInvalidDecl(); - - // C99 6.7.8p4. All file scoped initializers need to be constant. - CheckForConstantInitializer(Init, DclT); - } - // If the type changed, it means we had an incomplete type that was - // completed by the initializer. For example: - // int ary[] = { 1, 3, 5 }; - // "ary" transitions from a VariableArrayType to a ConstantArrayType. - if (!VDecl->isInvalidDecl() && (DclT != SavT)) { - VDecl->setType(DclT); - Init->setType(DclT); - } - - // Attach the initializer to the decl. - VDecl->setInit(Init); - return; -} - -/// The declarators are chained together backwards, reverse the list. -Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { - // Often we have single declarators, handle them quickly. - Decl *GroupDecl = static_cast(group); - if (GroupDecl == 0) - return 0; - - ScopedDecl *Group = dyn_cast(GroupDecl); - ScopedDecl *NewGroup = 0; - if (Group->getNextDeclarator() == 0) - NewGroup = Group; - else { // reverse the list. - while (Group) { - ScopedDecl *Next = Group->getNextDeclarator(); - Group->setNextDeclarator(NewGroup); - NewGroup = Group; - Group = Next; - } - } - // Perform semantic analysis that depends on having fully processed both - // the declarator and initializer. - for (ScopedDecl *ID = NewGroup; ID; ID = ID->getNextDeclarator()) { - VarDecl *IDecl = dyn_cast(ID); - if (!IDecl) - continue; - FileVarDecl *FVD = dyn_cast(IDecl); - BlockVarDecl *BVD = dyn_cast(IDecl); - QualType T = IDecl->getType(); - - // C99 6.7.5.2p2: If an identifier is declared to be an object with - // static storage duration, it shall not have a variable length array. - if ((FVD || BVD) && IDecl->getStorageClass() == VarDecl::Static) { - if (T->getAsVariableArrayType()) { - Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla); - IDecl->setInvalidDecl(); - } - } - // Block scope. C99 6.7p7: If an identifier for an object is declared with - // no linkage (C99 6.2.2p6), the type for the object shall be complete... - if (BVD && IDecl->getStorageClass() != VarDecl::Extern) { - if (T->isIncompleteType()) { - Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type, - T.getAsString()); - IDecl->setInvalidDecl(); - } - } - // File scope. C99 6.9.2p2: A declaration of an identifier for and - // object that has file scope without an initializer, and without a - // storage-class specifier or with the storage-class specifier "static", - // constitutes a tentative definition. Note: A tentative definition with - // external linkage is valid (C99 6.2.2p5). - if (FVD && !FVD->getInit() && (FVD->getStorageClass() == VarDecl::Static || - FVD->getStorageClass() == VarDecl::None)) { - if (T->isIncompleteArrayType()) { - // C99 6.9.2 (p2, p5): Implicit initialization causes an incomplete - // array to be completed. Don't issue a diagnostic. - } else if (T->isIncompleteType()) { - // C99 6.9.2p3: If the declaration of an identifier for an object is - // a tentative definition and has internal linkage (C99 6.2.2p3), the - // declared type shall not be an incomplete type. - Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type, - T.getAsString()); - IDecl->setInvalidDecl(); - } - } - } - return NewGroup; -} - -// Called from Sema::ParseStartOfFunctionDef(). -ParmVarDecl * -Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, - Scope *FnScope) { - IdentifierInfo *II = PI.Ident; - // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. - // Can this happen for params? We already checked that they don't conflict - // among each other. Here they can only shadow globals, which is ok. - if (/*Decl *PrevDecl = */LookupScopedDecl(II, Decl::IDNS_Ordinary, - PI.IdentLoc, FnScope)) { - - } - - // FIXME: Handle storage class (auto, register). No declarator? - // TODO: Chain to previous parameter with the prevdeclarator chain? - - // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). - // Doing the promotion here has a win and a loss. The win is the type for - // both Decl's and DeclRefExpr's will match (a convenient invariant for the - // code generator). The loss is the orginal type isn't preserved. For example: - // - // void func(int parmvardecl[5]) { // convert "int [5]" to "int *" - // int blockvardecl[5]; - // sizeof(parmvardecl); // size == 4 - // sizeof(blockvardecl); // size == 20 - // } - // - // For expressions, all implicit conversions are captured using the - // ImplicitCastExpr AST node (we have no such mechanism for Decl's). - // - // FIXME: If a source translation tool needs to see the original type, then - // we need to consider storing both types (in ParmVarDecl)... - // - QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo); - if (const ArrayType *AT = parmDeclType->getAsArrayType()) { - // int x[restrict 4] -> int *restrict - parmDeclType = Context.getPointerType(AT->getElementType()); - parmDeclType = parmDeclType.getQualifiedType(AT->getIndexTypeQualifier()); - } else if (parmDeclType->isFunctionType()) - parmDeclType = Context.getPointerType(parmDeclType); - - ParmVarDecl *New = ParmVarDecl::Create(Context, PI.IdentLoc, II, parmDeclType, - VarDecl::None, 0); - - if (PI.InvalidType) - New->setInvalidDecl(); - - // If this has an identifier, add it to the scope stack. - if (II) { - New->setNext(II->getFETokenInfo()); - II->setFETokenInfo(New); - FnScope->AddDecl(New); - } - - HandleDeclAttributes(New, PI.AttrList, 0); - return New; -} - -Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { - assert(CurFunctionDecl == 0 && "Function parsing confused"); - assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && - "Not a function declarator!"); - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; - - // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' - // for a K&R function. - if (!FTI.hasPrototype) { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - if (FTI.ArgInfo[i].TypeInfo == 0) { - Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared, - FTI.ArgInfo[i].Ident->getName()); - // Implicitly declare the argument as type 'int' for lack of a better - // type. - FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr(); - } - } - - // Since this is a function definition, act as though we have information - // about the arguments. - if (FTI.NumArgs) - FTI.hasPrototype = true; - } else { - // FIXME: Diagnose arguments without names in C. - - } - - Scope *GlobalScope = FnBodyScope->getParent(); - - // See if this is a redefinition. - ScopedDecl *PrevDcl = LookupScopedDecl(D.getIdentifier(), Decl::IDNS_Ordinary, - D.getIdentifierLoc(), GlobalScope); - if (FunctionDecl *FD = dyn_cast_or_null(PrevDcl)) { - if (FD->getBody()) { - Diag(D.getIdentifierLoc(), diag::err_redefinition, - D.getIdentifier()->getName()); - Diag(FD->getLocation(), diag::err_previous_definition); - } - } - Decl *decl = static_cast(ActOnDeclarator(GlobalScope, D, 0)); - FunctionDecl *FD = cast(decl); - CurFunctionDecl = FD; - - // Create Decl objects for each parameter, adding them to the FunctionDecl. - llvm::SmallVector Params; - - // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes - // no arguments, not a function that takes a single void argument. - if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && - !QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo).getCVRQualifiers() && - QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo)->isVoidType()) { - // empty arg list, don't push any params. - } else { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - Params.push_back(ActOnParamDeclarator(D.getTypeObject(0).Fun.ArgInfo[i], - FnBodyScope)); - } - } - - FD->setParams(&Params[0], Params.size()); - - return FD; -} - -Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtTy *Body) { - Decl *dcl = static_cast(D); - if (FunctionDecl *FD = dyn_cast(dcl)) { - FD->setBody((Stmt*)Body); - assert(FD == CurFunctionDecl && "Function parsing confused"); - CurFunctionDecl = 0; - } else if (ObjCMethodDecl *MD = dyn_cast(dcl)) { - MD->setBody((Stmt*)Body); - CurMethodDecl = 0; - } - // Verify and clean out per-function state. - - // Check goto/label use. - for (llvm::DenseMap::iterator - I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) { - // Verify that we have no forward references left. If so, there was a goto - // or address of a label taken, but no definition of it. Label fwd - // definitions are indicated with a null substmt. - if (I->second->getSubStmt() == 0) { - LabelStmt *L = I->second; - // Emit error. - Diag(L->getIdentLoc(), diag::err_undeclared_label_use, L->getName()); - - // At this point, we have gotos that use the bogus label. Stitch it into - // the function body so that they aren't leaked and that the AST is well - // formed. - if (Body) { - L->setSubStmt(new NullStmt(L->getIdentLoc())); - cast((Stmt*)Body)->push_back(L); - } else { - // The whole function wasn't parsed correctly, just delete this. - delete L; - } - } - } - LabelMap.clear(); - - return D; -} - -/// ImplicitlyDefineFunction - An undeclared identifier was used in a function -/// call, forming a call to an implicitly defined function (per C99 6.5.1p2). -ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, - IdentifierInfo &II, Scope *S) { - if (getLangOptions().C99) // Extension in C99. - Diag(Loc, diag::ext_implicit_function_decl, II.getName()); - else // Legal in C90, but warn about it. - Diag(Loc, diag::warn_implicit_function_decl, II.getName()); - - // FIXME: handle stuff like: - // void foo() { extern float X(); } - // void bar() { X(); } <-- implicit decl for X in another scope. - - // Set a Declarator for the implicit definition: int foo(); - const char *Dummy; - DeclSpec DS; - bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy); - Error = Error; // Silence warning. - assert(!Error && "Error setting up implicit decl!"); - Declarator D(DS, Declarator::BlockContext); - D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, Loc)); - D.SetIdentifier(&II, Loc); - - // Find translation-unit scope to insert this function into. - if (Scope *FnS = S->getFnParent()) - S = FnS->getParent(); // Skip all scopes in a function at once. - while (S->getParent()) - S = S->getParent(); - - return dyn_cast(static_cast(ActOnDeclarator(S, D, 0))); -} - - -TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - ScopedDecl *LastDeclarator) { - assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); - assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - - // Scope manipulation handled by caller. - TypedefDecl *NewTD = TypedefDecl::Create(Context, D.getIdentifierLoc(), - D.getIdentifier(), - T, LastDeclarator); - if (D.getInvalidType()) - NewTD->setInvalidDecl(); - return NewTD; -} - -/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the -/// former case, Name will be non-null. In the later case, Name will be null. -/// TagType indicates what kind of tag this is. TK indicates whether this is a -/// reference/declaration/definition of a tag. -Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, - SourceLocation KWLoc, IdentifierInfo *Name, - SourceLocation NameLoc, AttributeList *Attr) { - // If this is a use of an existing tag, it must have a name. - assert((Name != 0 || TK == TK_Definition) && - "Nameless record must be a definition!"); - - Decl::Kind Kind; - switch (TagType) { - default: assert(0 && "Unknown tag type!"); - case DeclSpec::TST_struct: Kind = Decl::Struct; break; - case DeclSpec::TST_union: Kind = Decl::Union; break; -//case DeclSpec::TST_class: Kind = Decl::Class; break; - case DeclSpec::TST_enum: Kind = Decl::Enum; break; - } - - // If this is a named struct, check to see if there was a previous forward - // declaration or definition. - if (TagDecl *PrevDecl = - dyn_cast_or_null(LookupScopedDecl(Name, Decl::IDNS_Tag, - NameLoc, S))) { - - // If this is a use of a previous tag, or if the tag is already declared in - // the same scope (so that the definition/declaration completes or - // rementions the tag), reuse the decl. - if (TK == TK_Reference || S->isDeclScope(PrevDecl)) { - // Make sure that this wasn't declared as an enum and now used as a struct - // or something similar. - if (PrevDecl->getKind() != Kind) { - Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_use); - } - - // If this is a use or a forward declaration, we're good. - if (TK != TK_Definition) - return PrevDecl; - - // Diagnose attempts to redefine a tag. - if (PrevDecl->isDefinition()) { - Diag(NameLoc, diag::err_redefinition, Name->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - // If this is a redefinition, recover by making this struct be - // anonymous, which will make any later references get the previous - // definition. - Name = 0; - } else { - // Okay, this is definition of a previously declared or referenced tag. - // Move the location of the decl to be the definition site. - PrevDecl->setLocation(NameLoc); - return PrevDecl; - } - } - // If we get here, this is a definition of a new struct type in a nested - // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new - // type. - } - - // If there is an identifier, use the location of the identifier as the - // location of the decl, otherwise use the location of the struct/union - // keyword. - SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; - - // Otherwise, if this is the first time we've seen this tag, create the decl. - TagDecl *New; - switch (Kind) { - default: assert(0 && "Unknown tag kind!"); - case Decl::Enum: - // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: - // enum X { A, B, C } D; D should chain to X. - New = EnumDecl::Create(Context, Loc, Name, 0); - // If this is an undefined enum, warn. - if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum); - break; - case Decl::Union: - case Decl::Struct: - case Decl::Class: - // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: - // struct X { int A; } D; D should chain to X. - New = RecordDecl::Create(Context, Kind, Loc, Name, 0); - break; - } - - // If this has an identifier, add it to the scope stack. - if (Name) { - // The scope passed in may not be a decl scope. Zip up the scope tree until - // we find one that is. - while ((S->getFlags() & Scope::DeclScope) == 0) - S = S->getParent(); - - // Add it to the decl chain. - New->setNext(Name->getFETokenInfo()); - Name->setFETokenInfo(New); - S->AddDecl(New); - } - - HandleDeclAttributes(New, Attr, 0); - return New; -} - -/// ActOnField - Each field of a struct/union/class is passed into this in order -/// to create a FieldDecl object for it. -Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagDecl, - SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { - IdentifierInfo *II = D.getIdentifier(); - Expr *BitWidth = (Expr*)BitfieldWidth; - SourceLocation Loc = DeclStart; - if (II) Loc = D.getIdentifierLoc(); - - // FIXME: Unnamed fields can be handled in various different ways, for - // example, unnamed unions inject all members into the struct namespace! - - - if (BitWidth) { - // TODO: Validate. - //printf("WARNING: BITFIELDS IGNORED!\n"); - - // 6.7.2.1p3 - // 6.7.2.1p4 - - } else { - // Not a bitfield. - - // validate II. - - } - - QualType T = GetTypeForDeclarator(D, S); - assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - bool InvalidDecl = false; - - // C99 6.7.2.1p8: A member of a structure or union may have any type other - // than a variably modified type. - if (T->isVariablyModifiedType()) { - // FIXME: This diagnostic needs work - Diag(Loc, diag::err_typecheck_illegal_vla, Loc); - InvalidDecl = true; - } - // FIXME: Chain fielddecls together. - FieldDecl *NewFD; - - if (isa(static_cast(TagDecl))) - NewFD = new FieldDecl(Loc, II, T, BitWidth); - else if (isa(static_cast(TagDecl)) || - isa(static_cast(TagDecl)) || - isa(static_cast(TagDecl)) || - // FIXME: ivars are currently used to model properties, and - // properties can appear within a protocol. - // See corresponding FIXME in DeclObjC.h:ObjCPropertyDecl. - isa(static_cast(TagDecl))) - NewFD = new ObjCIvarDecl(Loc, II, T); - else - assert(0 && "Sema::ActOnField(): Unknown TagDecl"); - - HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(), - D.getAttributes()); - - if (D.getInvalidType() || InvalidDecl) - NewFD->setInvalidDecl(); - return NewFD; -} - -/// TranslateIvarVisibility - Translate visibility from a token ID to an -/// AST enum value. -static ObjCIvarDecl::AccessControl -TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { - switch (ivarVisibility) { - case tok::objc_private: return ObjCIvarDecl::Private; - case tok::objc_public: return ObjCIvarDecl::Public; - case tok::objc_protected: return ObjCIvarDecl::Protected; - case tok::objc_package: return ObjCIvarDecl::Package; - default: assert(false && "Unknown visitibility kind"); - } -} - -void Sema::ActOnFields(Scope* S, - SourceLocation RecLoc, DeclTy *RecDecl, - DeclTy **Fields, unsigned NumFields, - SourceLocation LBrac, SourceLocation RBrac, - tok::ObjCKeywordKind *visibility) { - Decl *EnclosingDecl = static_cast(RecDecl); - assert(EnclosingDecl && "missing record or interface decl"); - RecordDecl *Record = dyn_cast(EnclosingDecl); - - if (Record && Record->isDefinition()) { - // Diagnose code like: - // struct S { struct S {} X; }; - // We discover this when we complete the outer S. Reject and ignore the - // outer S. - Diag(Record->getLocation(), diag::err_nested_redefinition, - Record->getKindName()); - Diag(RecLoc, diag::err_previous_definition); - Record->setInvalidDecl(); - return; - } - // Verify that all the fields are okay. - unsigned NumNamedMembers = 0; - llvm::SmallVector RecFields; - llvm::SmallSet FieldIDs; - - for (unsigned i = 0; i != NumFields; ++i) { - - FieldDecl *FD = cast_or_null(static_cast(Fields[i])); - assert(FD && "missing field decl"); - - // Remember all fields. - RecFields.push_back(FD); - - // Get the type for the field. - Type *FDTy = FD->getType().getTypePtr(); - - // If we have visibility info, make sure the AST is set accordingly. - if (visibility) - cast(FD)->setAccessControl( - TranslateIvarVisibility(visibility[i])); - - // C99 6.7.2.1p2 - A field may not be a function type. - if (FDTy->isFunctionType()) { - Diag(FD->getLocation(), diag::err_field_declared_as_function, - FD->getName()); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - // C99 6.7.2.1p2 - A field may not be an incomplete type except... - if (FDTy->isIncompleteType()) { - if (!Record) { // Incomplete ivar type is always an error. - Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName()); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - if (i != NumFields-1 || // ... that the last member ... - Record->getKind() != Decl::Struct || // ... of a structure ... - !FDTy->isArrayType()) { //... may have incomplete array type. - Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName()); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - if (NumNamedMembers < 1) { //... must have more than named member ... - Diag(FD->getLocation(), diag::err_flexible_array_empty_struct, - FD->getName()); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - // Okay, we have a legal flexible array member at the end of the struct. - if (Record) - Record->setHasFlexibleArrayMember(true); - } - /// C99 6.7.2.1p2 - a struct ending in a flexible array member cannot be the - /// field of another structure or the element of an array. - if (const RecordType *FDTTy = FDTy->getAsRecordType()) { - if (FDTTy->getDecl()->hasFlexibleArrayMember()) { - // If this is a member of a union, then entire union becomes "flexible". - if (Record && Record->getKind() == Decl::Union) { - Record->setHasFlexibleArrayMember(true); - } else { - // If this is a struct/class and this is not the last element, reject - // it. Note that GCC supports variable sized arrays in the middle of - // structures. - if (i != NumFields-1) { - Diag(FD->getLocation(), diag::err_variable_sized_type_in_struct, - FD->getName()); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - // We support flexible arrays at the end of structs in other structs - // as an extension. - Diag(FD->getLocation(), diag::ext_flexible_array_in_struct, - FD->getName()); - if (Record) - Record->setHasFlexibleArrayMember(true); - } - } - } - /// A field cannot be an Objective-c object - if (FDTy->isObjCInterfaceType()) { - Diag(FD->getLocation(), diag::err_statically_allocated_object, - FD->getName()); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - // Keep track of the number of named members. - if (IdentifierInfo *II = FD->getIdentifier()) { - // Detect duplicate member names. - if (!FieldIDs.insert(II)) { - Diag(FD->getLocation(), diag::err_duplicate_member, II->getName()); - // Find the previous decl. - SourceLocation PrevLoc; - for (unsigned i = 0, e = RecFields.size(); ; ++i) { - assert(i != e && "Didn't find previous def!"); - if (RecFields[i]->getIdentifier() == II) { - PrevLoc = RecFields[i]->getLocation(); - break; - } - } - Diag(PrevLoc, diag::err_previous_definition); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; - } - ++NumNamedMembers; - } - } - - // Okay, we successfully defined 'Record'. - if (Record) { - Record->defineBody(&RecFields[0], RecFields.size()); - Consumer.HandleTagDeclDefinition(Record); - } else { - ObjCIvarDecl **ClsFields = reinterpret_cast(&RecFields[0]); - if (ObjCInterfaceDecl *ID = dyn_cast(EnclosingDecl)) - ID->addInstanceVariablesToClass(ClsFields, RecFields.size(), RBrac); - else if (ObjCImplementationDecl *IMPDecl = - dyn_cast(EnclosingDecl)) { - assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); - IMPDecl->ObjCAddInstanceVariablesToClassImpl(ClsFields, RecFields.size()); - CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); - } - } -} - -Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, - DeclTy *lastEnumConst, - SourceLocation IdLoc, IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *val) { - theEnumDecl = theEnumDecl; // silence unused warning. - EnumConstantDecl *LastEnumConst = - cast_or_null(static_cast(lastEnumConst)); - Expr *Val = static_cast(val); - - // The scope passed in may not be a decl scope. Zip up the scope tree until - // we find one that is. - while ((S->getFlags() & Scope::DeclScope) == 0) - S = S->getParent(); - - // Verify that there isn't already something declared with this name in this - // scope. - if (ScopedDecl *PrevDecl = LookupScopedDecl(Id, Decl::IDNS_Ordinary, - IdLoc, S)) { - if (S->isDeclScope(PrevDecl)) { - if (isa(PrevDecl)) - Diag(IdLoc, diag::err_redefinition_of_enumerator, Id->getName()); - else - Diag(IdLoc, diag::err_redefinition, Id->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - delete Val; - return 0; - } - } - - llvm::APSInt EnumVal(32); - QualType EltTy; - if (Val) { - // Make sure to promote the operand type to int. - UsualUnaryConversions(Val); - - // C99 6.7.2.2p2: Make sure we have an integer constant expression. - SourceLocation ExpLoc; - if (!Val->isIntegerConstantExpr(EnumVal, Context, &ExpLoc)) { - Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr, - Id->getName()); - delete Val; - Val = 0; // Just forget about it. - } else { - EltTy = Val->getType(); - } - } - - if (!Val) { - if (LastEnumConst) { - // Assign the last value + 1. - EnumVal = LastEnumConst->getInitVal(); - ++EnumVal; - - // Check for overflow on increment. - if (EnumVal < LastEnumConst->getInitVal()) - Diag(IdLoc, diag::warn_enum_value_overflow); - - EltTy = LastEnumConst->getType(); - } else { - // First value, set to zero. - EltTy = Context.IntTy; - EnumVal.zextOrTrunc(static_cast(Context.getTypeSize(EltTy))); - } - } - - EnumConstantDecl *New = - EnumConstantDecl::Create(Context, IdLoc, Id, EltTy, Val, EnumVal, - LastEnumConst); - - // Register this decl in the current scope stack. - New->setNext(Id->getFETokenInfo()); - Id->setFETokenInfo(New); - S->AddDecl(New); - return New; -} - -void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, - DeclTy **Elements, unsigned NumElements) { - EnumDecl *Enum = cast(static_cast(EnumDeclX)); - assert(!Enum->isDefinition() && "Enum redefinitions can't reach here"); - - // TODO: If the result value doesn't fit in an int, it must be a long or long - // long value. ISO C does not support this, but GCC does as an extension, - // emit a warning. - unsigned IntWidth = Context.Target.getIntWidth(); - - // Verify that all the values are okay, compute the size of the values, and - // reverse the list. - unsigned NumNegativeBits = 0; - unsigned NumPositiveBits = 0; - - // Keep track of whether all elements have type int. - bool AllElementsInt = true; - - EnumConstantDecl *EltList = 0; - for (unsigned i = 0; i != NumElements; ++i) { - EnumConstantDecl *ECD = - cast_or_null(static_cast(Elements[i])); - if (!ECD) continue; // Already issued a diagnostic. - - // If the enum value doesn't fit in an int, emit an extension warning. - const llvm::APSInt &InitVal = ECD->getInitVal(); - assert(InitVal.getBitWidth() >= IntWidth && - "Should have promoted value to int"); - if (InitVal.getBitWidth() > IntWidth) { - llvm::APSInt V(InitVal); - V.trunc(IntWidth); - V.extend(InitVal.getBitWidth()); - if (V != InitVal) - Diag(ECD->getLocation(), diag::ext_enum_value_not_int, - InitVal.toString()); - } - - // Keep track of the size of positive and negative values. - if (InitVal.isUnsigned() || InitVal.isNonNegative()) - NumPositiveBits = std::max(NumPositiveBits, - (unsigned)InitVal.getActiveBits()); - else - NumNegativeBits = std::max(NumNegativeBits, - (unsigned)InitVal.getMinSignedBits()); - - // Keep track of whether every enum element has type int (very commmon). - if (AllElementsInt) - AllElementsInt = ECD->getType() == Context.IntTy; - - ECD->setNextDeclarator(EltList); - EltList = ECD; - } - - // Figure out the type that should be used for this enum. - // FIXME: Support attribute(packed) on enums and -fshort-enums. - QualType BestType; - unsigned BestWidth; - - if (NumNegativeBits) { - // If there is a negative value, figure out the smallest integer type (of - // int/long/longlong) that fits. - if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { - BestType = Context.IntTy; - BestWidth = IntWidth; - } else { - BestWidth = Context.Target.getLongWidth(); - - if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) - BestType = Context.LongTy; - else { - BestWidth = Context.Target.getLongLongWidth(); - - if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) - Diag(Enum->getLocation(), diag::warn_enum_too_large); - BestType = Context.LongLongTy; - } - } - } else { - // If there is no negative value, figure out which of uint, ulong, ulonglong - // fits. - if (NumPositiveBits <= IntWidth) { - BestType = Context.UnsignedIntTy; - BestWidth = IntWidth; - } else if (NumPositiveBits <= - (BestWidth = Context.Target.getLongWidth())) { - BestType = Context.UnsignedLongTy; - } else { - BestWidth = Context.Target.getLongLongWidth(); - assert(NumPositiveBits <= BestWidth && - "How could an initializer get larger than ULL?"); - BestType = Context.UnsignedLongLongTy; - } - } - - // Loop over all of the enumerator constants, changing their types to match - // the type of the enum if needed. - for (unsigned i = 0; i != NumElements; ++i) { - EnumConstantDecl *ECD = - cast_or_null(static_cast(Elements[i])); - if (!ECD) continue; // Already issued a diagnostic. - - // Standard C says the enumerators have int type, but we allow, as an - // extension, the enumerators to be larger than int size. If each - // enumerator value fits in an int, type it as an int, otherwise type it the - // same as the enumerator decl itself. This means that in "enum { X = 1U }" - // that X has type 'int', not 'unsigned'. - if (ECD->getType() == Context.IntTy) { - // Make sure the init value is signed. - llvm::APSInt IV = ECD->getInitVal(); - IV.setIsSigned(true); - ECD->setInitVal(IV); - continue; // Already int type. - } - - // Determine whether the value fits into an int. - llvm::APSInt InitVal = ECD->getInitVal(); - bool FitsInInt; - if (InitVal.isUnsigned() || !InitVal.isNegative()) - FitsInInt = InitVal.getActiveBits() < IntWidth; - else - FitsInInt = InitVal.getMinSignedBits() <= IntWidth; - - // If it fits into an integer type, force it. Otherwise force it to match - // the enum decl type. - QualType NewTy; - unsigned NewWidth; - bool NewSign; - if (FitsInInt) { - NewTy = Context.IntTy; - NewWidth = IntWidth; - NewSign = true; - } else if (ECD->getType() == BestType) { - // Already the right type! - continue; - } else { - NewTy = BestType; - NewWidth = BestWidth; - NewSign = BestType->isSignedIntegerType(); - } - - // Adjust the APSInt value. - InitVal.extOrTrunc(NewWidth); - InitVal.setIsSigned(NewSign); - ECD->setInitVal(InitVal); - - // Adjust the Expr initializer and type. - ECD->setInitExpr(new ImplicitCastExpr(NewTy, ECD->getInitExpr())); - ECD->setType(NewTy); - } - - Enum->defineElements(EltList, BestType); - Consumer.HandleTagDeclDefinition(Enum); -} - -Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, - ExprTy *expr) { - StringLiteral *AsmString = cast((Expr*)expr); - - return new FileScopeAsmDecl(Loc, AsmString); -} - -Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc, - SourceLocation LBrace, - SourceLocation RBrace, - const char *Lang, - unsigned StrSize, - DeclTy *D) { - LinkageSpecDecl::LanguageIDs Language; - Decl *dcl = static_cast(D); - if (strncmp(Lang, "\"C\"", StrSize) == 0) - Language = LinkageSpecDecl::lang_c; - else if (strncmp(Lang, "\"C++\"", StrSize) == 0) - Language = LinkageSpecDecl::lang_cxx; - else { - Diag(Loc, diag::err_bad_language); - return 0; - } - - // FIXME: Add all the various semantics of linkage specifications - return new LinkageSpecDecl(Loc, Language, dcl); -} - -void Sema::HandleDeclAttribute(Decl *New, AttributeList *Attr) { - - switch (Attr->getKind()) { - case AttributeList::AT_vector_size: - if (ValueDecl *vDecl = dyn_cast(New)) { - QualType newType = HandleVectorTypeAttribute(vDecl->getType(), Attr); - if (!newType.isNull()) // install the new vector type into the decl - vDecl->setType(newType); - } - if (TypedefDecl *tDecl = dyn_cast(New)) { - QualType newType = HandleVectorTypeAttribute(tDecl->getUnderlyingType(), - Attr); - if (!newType.isNull()) // install the new vector type into the decl - tDecl->setUnderlyingType(newType); - } - break; - case AttributeList::AT_ocu_vector_type: - if (TypedefDecl *tDecl = dyn_cast(New)) - HandleOCUVectorTypeAttribute(tDecl, Attr); - else - Diag(Attr->getLoc(), - diag::err_typecheck_ocu_vector_not_typedef); - break; - case AttributeList::AT_address_space: - if (TypedefDecl *tDecl = dyn_cast(New)) { - QualType newType = HandleAddressSpaceTypeAttribute( - tDecl->getUnderlyingType(), - Attr); - tDecl->setUnderlyingType(newType); - } else if (ValueDecl *vDecl = dyn_cast(New)) { - QualType newType = HandleAddressSpaceTypeAttribute(vDecl->getType(), - Attr); - // install the new addr spaced type into the decl - vDecl->setType(newType); - } - break; - case AttributeList::AT_deprecated: - HandleDeprecatedAttribute(New, Attr); - break; - case AttributeList::AT_visibility: - HandleVisibilityAttribute(New, Attr); - break; - case AttributeList::AT_weak: - HandleWeakAttribute(New, Attr); - break; - case AttributeList::AT_dllimport: - HandleDLLImportAttribute(New, Attr); - break; - case AttributeList::AT_dllexport: - HandleDLLExportAttribute(New, Attr); - break; - case AttributeList::AT_nothrow: - HandleNothrowAttribute(New, Attr); - break; - case AttributeList::AT_stdcall: - HandleStdCallAttribute(New, Attr); - break; - case AttributeList::AT_fastcall: - HandleFastCallAttribute(New, Attr); - break; - case AttributeList::AT_aligned: - HandleAlignedAttribute(New, Attr); - break; - case AttributeList::AT_packed: - HandlePackedAttribute(New, Attr); - break; - case AttributeList::AT_annotate: - HandleAnnotateAttribute(New, Attr); - break; - case AttributeList::AT_noreturn: - HandleNoReturnAttribute(New, Attr); - break; - case AttributeList::AT_format: - HandleFormatAttribute(New, Attr); - break; - default: -#if 0 - // TODO: when we have the full set of attributes, warn about unknown ones. - Diag(Attr->getLoc(), diag::warn_attribute_ignored, - Attr->getName()->getName()); -#endif - break; - } -} - -void Sema::HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix, - AttributeList *declarator_postfix) { - while (declspec_prefix) { - HandleDeclAttribute(New, declspec_prefix); - declspec_prefix = declspec_prefix->getNext(); - } - while (declarator_postfix) { - HandleDeclAttribute(New, declarator_postfix); - declarator_postfix = declarator_postfix->getNext(); - } -} - -void Sema::HandleOCUVectorTypeAttribute(TypedefDecl *tDecl, - AttributeList *rawAttr) { - QualType curType = tDecl->getUnderlyingType(); - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - Expr *sizeExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, - "ocu_vector_type", sizeExpr->getSourceRange()); - return; - } - // unlike gcc's vector_size attribute, we do not allow vectors to be defined - // in conjunction with complex types (pointers, arrays, functions, etc.). - Type *canonType = curType.getCanonicalType().getTypePtr(); - if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { - Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, - curType.getCanonicalType().getAsString()); - return; - } - // unlike gcc's vector_size attribute, the size is specified as the - // number of elements, not the number of bytes. - unsigned vectorSize = static_cast(vecSize.getZExtValue()); - - if (vectorSize == 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, - sizeExpr->getSourceRange()); - return; - } - // Instantiate/Install the vector type, the number of elements is > 0. - tDecl->setUnderlyingType(Context.getOCUVectorType(curType, vectorSize)); - // Remember this typedef decl, we will need it later for diagnostics. - OCUVectorDecls.push_back(tDecl); -} - -QualType Sema::HandleVectorTypeAttribute(QualType curType, - AttributeList *rawAttr) { - // check the attribute arugments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return QualType(); - } - Expr *sizeExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, - "vector_size", sizeExpr->getSourceRange()); - return QualType(); - } - // navigate to the base type - we need to provide for vector pointers, - // vector arrays, and functions returning vectors. - Type *canonType = curType.getCanonicalType().getTypePtr(); - - if (canonType->isPointerType() || canonType->isArrayType() || - canonType->isFunctionType()) { - assert(0 && "HandleVector(): Complex type construction unimplemented"); - /* FIXME: rebuild the type from the inside out, vectorizing the inner type. - do { - if (PointerType *PT = dyn_cast(canonType)) - canonType = PT->getPointeeType().getTypePtr(); - else if (ArrayType *AT = dyn_cast(canonType)) - canonType = AT->getElementType().getTypePtr(); - else if (FunctionType *FT = dyn_cast(canonType)) - canonType = FT->getResultType().getTypePtr(); - } while (canonType->isPointerType() || canonType->isArrayType() || - canonType->isFunctionType()); - */ - } - // the base type must be integer or float. - if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { - Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, - curType.getCanonicalType().getAsString()); - return QualType(); - } - unsigned typeSize = static_cast(Context.getTypeSize(curType)); - // vecSize is specified in bytes - convert to bits. - unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); - - // the vector size needs to be an integral multiple of the type size. - if (vectorSize % typeSize) { - Diag(rawAttr->getLoc(), diag::err_attribute_invalid_size, - sizeExpr->getSourceRange()); - return QualType(); - } - if (vectorSize == 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, - sizeExpr->getSourceRange()); - return QualType(); - } - // Instantiate the vector type, the number of elements is > 0, and not - // required to be a power of 2, unlike GCC. - return Context.getVectorType(curType, vectorSize/typeSize); -} - -void Sema::HandlePackedAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() > 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - if (TagDecl *TD = dyn_cast(d)) - TD->addAttr(new PackedAttr); - else if (FieldDecl *FD = dyn_cast(d)) { - // If the alignment is less than or equal to 8 bits, the packed attribute - // has no effect. - if (Context.getTypeAlign(FD->getType()) <= 8) - Diag(rawAttr->getLoc(), - diag::warn_attribute_ignored_for_field_of_type, - rawAttr->getName()->getName(), FD->getType().getAsString()); - else - FD->addAttr(new PackedAttr); - } else - Diag(rawAttr->getLoc(), diag::warn_attribute_ignored, - rawAttr->getName()->getName()); -} - -void Sema::HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - FunctionDecl *Fn = dyn_cast(d); - - if (!Fn) { - Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, - "noreturn", "function"); - return; - } - - d->addAttr(new NoReturnAttr()); -} - -void Sema::HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new DeprecatedAttr()); -} - -void Sema::HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - - Expr *Arg = static_cast(rawAttr->getArg(0)); - Arg = Arg->IgnoreParenCasts(); - StringLiteral *Str = dyn_cast(Arg); - - if (Str == 0 || Str->isWide()) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, - "visibility", std::string("1")); - return; - } - - const char *TypeStr = Str->getStrData(); - unsigned TypeLen = Str->getByteLength(); - llvm::GlobalValue::VisibilityTypes type; - - if (TypeLen == 7 && !memcmp(TypeStr, "default", 7)) - type = llvm::GlobalValue::DefaultVisibility; - else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6)) - type = llvm::GlobalValue::HiddenVisibility; - else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8)) - type = llvm::GlobalValue::HiddenVisibility; // FIXME - else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9)) - type = llvm::GlobalValue::ProtectedVisibility; - else { - Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, - "visibility", TypeStr); - return; - } - - d->addAttr(new VisibilityAttr(type)); -} - -void Sema::HandleWeakAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new WeakAttr()); -} - -void Sema::HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new DLLImportAttr()); -} - -void Sema::HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new DLLExportAttr()); -} - -void Sema::HandleStdCallAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new StdCallAttr()); -} - -void Sema::HandleFastCallAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new FastCallAttr()); -} - -void Sema::HandleNothrowAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 0) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("0")); - return; - } - - d->addAttr(new NoThrowAttr()); -} - -/// Handle __attribute__((format(type,idx,firstarg))) attributes -/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) { - - if (!rawAttr->getParameterName()) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, - "format", std::string("1")); - return; - } - - if (rawAttr->getNumArgs() != 2) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("3")); - return; - } - - FunctionDecl *Fn = dyn_cast(d); - if (!Fn) { - Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, - "format", "function"); - return; - } - - const FunctionTypeProto *proto = - dyn_cast(Fn->getType()->getAsFunctionType()); - if (!proto) - return; - - // FIXME: in C++ the implicit 'this' function parameter also counts. - // this is needed in order to be compatible with GCC - // the index must start in 1 and the limit is numargs+1 - unsigned NumArgs = Fn->getNumParams(); - unsigned FirstIdx = 1; - - const char *Format = rawAttr->getParameterName()->getName(); - unsigned FormatLen = rawAttr->getParameterName()->getLength(); - - // Normalize the argument, __foo__ becomes foo. - if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && - Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { - Format += 2; - FormatLen -= 4; - } - - if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5)) - || (FormatLen == 6 && !memcmp(Format, "printf", 6)) - || (FormatLen == 7 && !memcmp(Format, "strfmon", 7)) - || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) { - Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, - "format", rawAttr->getParameterName()->getName()); - return; - } - - // checks for the 2nd argument - Expr *IdxExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt Idx(Context.getTypeSize(IdxExpr->getType())); - if (!IdxExpr->isIntegerConstantExpr(Idx, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, - "format", std::string("2"), IdxExpr->getSourceRange()); - return; - } - - if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, - "format", std::string("2"), IdxExpr->getSourceRange()); - return; - } - - // make sure the format string is really a string - QualType Ty = proto->getArgType(Idx.getZExtValue()-1); - if (!Ty->isPointerType() || - !Ty->getAsPointerType()->getPointeeType()->isCharType()) { - Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string, - IdxExpr->getSourceRange()); - return; - } - - - // check the 3rd argument - Expr *FirstArgExpr = static_cast(rawAttr->getArg(1)); - llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType())); - if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, - "format", std::string("3"), FirstArgExpr->getSourceRange()); - return; - } - - // check if the function is variadic if the 3rd argument non-zero - if (FirstArg != 0) { - if (proto->isVariadic()) { - ++NumArgs; // +1 for ... - } else { - Diag(d->getLocation(), diag::err_format_attribute_requires_variadic); - return; - } - } - - // strftime requires FirstArg to be 0 because it doesn't read from any variable - // the input is just the current time + the format string - if (FormatLen == 8 && !memcmp(Format, "strftime", 8)) { - if (FirstArg != 0) { - Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter, - FirstArgExpr->getSourceRange()); - return; - } - // if 0 it disables parameter checking (to use with e.g. va_list) - } else if (FirstArg != 0 && FirstArg != NumArgs) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, - "format", std::string("3"), FirstArgExpr->getSourceRange()); - return; - } - - d->addAttr(new FormatAttr(std::string(Format, FormatLen), - Idx.getZExtValue(), FirstArg.getZExtValue())); -} - -void Sema::HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr) { - // check the attribute arguments. - if (rawAttr->getNumArgs() != 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - Expr *argExpr = static_cast(rawAttr->getArg(0)); - StringLiteral *SE = dyn_cast(argExpr); - - // Make sure that there is a string literal as the annotation's single - // argument. - if (!SE) { - Diag(rawAttr->getLoc(), diag::err_attribute_annotate_no_string); - return; - } - d->addAttr(new AnnotateAttr(std::string(SE->getStrData(), - SE->getByteLength()))); -} - -void Sema::HandleAlignedAttribute(Decl *d, AttributeList *rawAttr) -{ - // check the attribute arguments. - if (rawAttr->getNumArgs() > 1) { - Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return; - } - - unsigned Align = 0; - - if (rawAttr->getNumArgs() == 0) { - // FIXME: This should be the target specific maximum alignment. - // (For now we just use 128 bits which is the maximum on X86. - Align = 128; - return; - } else { - Expr *alignmentExpr = static_cast(rawAttr->getArg(0)); - llvm::APSInt alignment(32); - if (!alignmentExpr->isIntegerConstantExpr(alignment, Context)) { - Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, - "aligned", alignmentExpr->getSourceRange()); - return; - } - - Align = alignment.getZExtValue() * 8; - } - - d->addAttr(new AlignedAttr(Align)); -} diff --git a/clang/Sema/SemaDeclObjC.cpp b/clang/Sema/SemaDeclObjC.cpp deleted file mode 100644 index 20d127b31eb..00000000000 --- a/clang/Sema/SemaDeclObjC.cpp +++ /dev/null @@ -1,927 +0,0 @@ -//===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for Objective C declarations. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Parse/Scope.h" - -using namespace clang; - -/// ObjCActOnStartOfMethodDef - This routine sets up parameters; invisible -/// and user declared, in the method definition's AST. -void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { - assert(CurFunctionDecl == 0 && "Method parsing confused"); - ObjCMethodDecl *MDecl = dyn_cast(static_cast(D)); - assert(MDecl != 0 && "Not a method declarator!"); - - // Allow the rest of sema to find private method decl implementations. - if (MDecl->isInstance()) - AddInstanceMethodToGlobalPool(MDecl); - else - AddFactoryMethodToGlobalPool(MDecl); - - // Allow all of Sema to see that we are entering a method definition. - CurMethodDecl = MDecl; - - // Create Decl objects for each parameter, entrring them in the scope for - // binding to their use. - struct DeclaratorChunk::ParamInfo PI; - - // Insert the invisible arguments, self and _cmd! - PI.Ident = &Context.Idents.get("self"); - PI.IdentLoc = SourceLocation(); // synthesized vars have a null location. - PI.InvalidType = false; - PI.AttrList = 0; - PI.TypeInfo = Context.getObjCIdType().getAsOpaquePtr(); - - if (MDecl->isInstance()) { - if (ObjCInterfaceDecl *OID = MDecl->getClassInterface()) { - // There may be no interface context due to error in declaration of the - // interface (which has been reported). Recover gracefully - QualType selfTy = Context.getObjCInterfaceType(OID); - selfTy = Context.getPointerType(selfTy); - PI.TypeInfo = selfTy.getAsOpaquePtr(); - } - } - - CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope)); - - PI.Ident = &Context.Idents.get("_cmd"); - PI.TypeInfo = Context.getObjCSelType().getAsOpaquePtr(); - ActOnParamDeclarator(PI, FnBodyScope); - - for (int i = 0; i < MDecl->getNumParams(); i++) { - ParmVarDecl *PDecl = MDecl->getParamDecl(i); - PI.Ident = PDecl->getIdentifier(); - PI.IdentLoc = PDecl->getLocation(); // user vars have a real location. - PI.TypeInfo = PDecl->getType().getAsOpaquePtr(); - MDecl->setParamDecl(i, ActOnParamDeclarator(PI, FnBodyScope)); - } -} - -Sema::DeclTy *Sema::ActOnStartClassInterface( - SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperName, SourceLocation SuperLoc, - IdentifierInfo **ProtocolNames, unsigned NumProtocols, - SourceLocation EndProtoLoc, AttributeList *AttrList) { - assert(ClassName && "Missing class identifier"); - - // Check for another declaration kind with the same name. - ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); - if (PrevDecl && !isa(PrevDecl)) { - Diag(ClassLoc, diag::err_redefinition_different_kind, - ClassName->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - - ObjCInterfaceDecl* IDecl = dyn_cast_or_null(PrevDecl); - if (IDecl) { - // Class already seen. Is it a forward declaration? - if (!IDecl->isForwardDecl()) - Diag(AtInterfaceLoc, diag::err_duplicate_class_def, IDecl->getName()); - else { - IDecl->setLocation(AtInterfaceLoc); - IDecl->setForwardDecl(false); - IDecl->AllocIntfRefProtocols(NumProtocols); - } - } - else { - IDecl = new ObjCInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName); - - // Chain & install the interface decl into the identifier. - IDecl->setNext(ClassName->getFETokenInfo()); - ClassName->setFETokenInfo(IDecl); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IDecl); - } - - if (SuperName) { - ObjCInterfaceDecl* SuperClassEntry = 0; - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupInterfaceDecl(SuperName); - if (PrevDecl && !isa(PrevDecl)) { - Diag(SuperLoc, diag::err_redefinition_different_kind, - SuperName->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - else { - // Check that super class is previously defined - SuperClassEntry = dyn_cast_or_null(PrevDecl); - - if (!SuperClassEntry || SuperClassEntry->isForwardDecl()) { - Diag(AtInterfaceLoc, diag::err_undef_superclass, - SuperClassEntry ? SuperClassEntry->getName() - : SuperName->getName(), - ClassName->getName()); - } - } - IDecl->setSuperClass(SuperClassEntry); - IDecl->setLocEnd(SuperLoc); - } else { // we have a root class. - IDecl->setLocEnd(ClassLoc); - } - - /// Check then save referenced protocols - if (NumProtocols) { - for (unsigned int i = 0; i != NumProtocols; i++) { - ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtocolNames[i]]; - if (!RefPDecl || RefPDecl->isForwardDecl()) - Diag(ClassLoc, diag::warn_undef_protocolref, - ProtocolNames[i]->getName(), - ClassName->getName()); - IDecl->setIntfRefProtocols(i, RefPDecl); - } - IDecl->setLocEnd(EndProtoLoc); - } - return IDecl; -} - -/// ActOnCompatiblityAlias - this action is called after complete parsing of -/// @compaatibility_alias declaration. It sets up the alias relationships. -Sema::DeclTy *Sema::ActOnCompatiblityAlias( - SourceLocation AtCompatibilityAliasLoc, - IdentifierInfo *AliasName, SourceLocation AliasLocation, - IdentifierInfo *ClassName, SourceLocation ClassLocation) { - // Look for previous declaration of alias name - ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary, - AliasLocation, TUScope); - if (ADecl) { - if (isa(ADecl)) { - Diag(AliasLocation, diag::warn_previous_alias_decl); - Diag(ADecl->getLocation(), diag::warn_previous_declaration); - } - else { - Diag(AliasLocation, diag::err_conflicting_aliasing_type, - AliasName->getName()); - Diag(ADecl->getLocation(), diag::err_previous_declaration); - } - return 0; - } - // Check for class declaration - ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary, - ClassLocation, TUScope); - if (!CDecl || !isa(CDecl)) { - Diag(ClassLocation, diag::warn_undef_interface, - ClassName->getName()); - if (CDecl) - Diag(CDecl->getLocation(), diag::warn_previous_declaration); - return 0; - } - // Everything checked out, instantiate a new alias declaration ast - ObjCCompatibleAliasDecl *AliasDecl = - new ObjCCompatibleAliasDecl(AtCompatibilityAliasLoc, - AliasName, - dyn_cast(CDecl)); - - // Chain & install the interface decl into the identifier. - AliasDecl->setNext(AliasName->getFETokenInfo()); - AliasName->setFETokenInfo(AliasDecl); - return AliasDecl; -} - -Sema::DeclTy *Sema::ActOnStartProtocolInterface( - SourceLocation AtProtoInterfaceLoc, - IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, - IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc) { - assert(ProtocolName && "Missing protocol identifier"); - ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolName]; - if (PDecl) { - // Protocol already seen. Better be a forward protocol declaration - if (!PDecl->isForwardDecl()) - Diag(ProtocolLoc, diag::err_duplicate_protocol_def, - ProtocolName->getName()); - else { - PDecl->setForwardDecl(false); - PDecl->AllocReferencedProtocols(NumProtoRefs); - } - } - else { - PDecl = new ObjCProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs, - ProtocolName); - ObjCProtocols[ProtocolName] = PDecl; - } - - if (NumProtoRefs) { - /// Check then save referenced protocols - for (unsigned int i = 0; i != NumProtoRefs; i++) { - ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtoRefNames[i]]; - if (!RefPDecl || RefPDecl->isForwardDecl()) - Diag(ProtocolLoc, diag::warn_undef_protocolref, - ProtoRefNames[i]->getName(), - ProtocolName->getName()); - PDecl->setReferencedProtocols(i, RefPDecl); - } - PDecl->setLocEnd(EndProtoLoc); - } - return PDecl; -} - -/// FindProtocolDeclaration - This routine looks up protocols and -/// issuer error if they are not declared. It returns list of protocol -/// declarations in its 'Protocols' argument. -void -Sema::FindProtocolDeclaration(SourceLocation TypeLoc, - IdentifierInfo **ProtocolId, - unsigned NumProtocols, - llvm::SmallVector &Protocols) { - for (unsigned i = 0; i != NumProtocols; ++i) { - ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolId[i]]; - if (!PDecl) - Diag(TypeLoc, diag::err_undeclared_protocol, - ProtocolId[i]->getName()); - else - Protocols.push_back(PDecl); - } -} - -/// ActOnForwardProtocolDeclaration - -Action::DeclTy * -Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, - IdentifierInfo **IdentList, unsigned NumElts) { - llvm::SmallVector Protocols; - - for (unsigned i = 0; i != NumElts; ++i) { - IdentifierInfo *P = IdentList[i]; - ObjCProtocolDecl *PDecl = ObjCProtocols[P]; - if (!PDecl) { // Not already seen? - // FIXME: Pass in the location of the identifier! - PDecl = new ObjCProtocolDecl(AtProtocolLoc, 0, P, true); - ObjCProtocols[P] = PDecl; - } - - Protocols.push_back(PDecl); - } - return new ObjCForwardProtocolDecl(AtProtocolLoc, - &Protocols[0], Protocols.size()); -} - -Sema::DeclTy *Sema::ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, - IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, - SourceLocation EndProtoLoc) { - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); - - ObjCCategoryDecl *CDecl = new ObjCCategoryDecl(AtInterfaceLoc, NumProtoRefs, - CategoryName); - CDecl->setClassInterface(IDecl); - - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) - Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); - else { - /// Check for duplicate interface declaration for this category - ObjCCategoryDecl *CDeclChain; - for (CDeclChain = IDecl->getCategoryList(); CDeclChain; - CDeclChain = CDeclChain->getNextClassCategory()) { - if (CDeclChain->getIdentifier() == CategoryName) { - Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(), - CategoryName->getName()); - break; - } - } - if (!CDeclChain) - CDecl->insertNextClassCategory(); - } - - if (NumProtoRefs) { - /// Check then save referenced protocols - for (unsigned int i = 0; i != NumProtoRefs; i++) { - ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtoRefNames[i]]; - if (!RefPDecl || RefPDecl->isForwardDecl()) { - Diag(CategoryLoc, diag::warn_undef_protocolref, - ProtoRefNames[i]->getName(), - CategoryName->getName()); - } - CDecl->setCatReferencedProtocols(i, RefPDecl); - } - CDecl->setLocEnd(EndProtoLoc); - } - return CDecl; -} - -/// ActOnStartCategoryImplementation - Perform semantic checks on the -/// category implementation declaration and build an ObjCCategoryImplDecl -/// object. -Sema::DeclTy *Sema::ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *CatName, SourceLocation CatLoc) { - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); - ObjCCategoryImplDecl *CDecl = new ObjCCategoryImplDecl(AtCatImplLoc, - CatName, IDecl); - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) - Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); - - /// TODO: Check that CatName, category name, is not used in another - // implementation. - return CDecl; -} - -Sema::DeclTy *Sema::ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc) { - ObjCInterfaceDecl* IDecl = 0; - // Check for another declaration kind with the same name. - ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); - if (PrevDecl && !isa(PrevDecl)) { - Diag(ClassLoc, diag::err_redefinition_different_kind, - ClassName->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - else { - // Is there an interface declaration of this class; if not, warn! - IDecl = dyn_cast_or_null(PrevDecl); - if (!IDecl) - Diag(ClassLoc, diag::warn_undef_interface, ClassName->getName()); - } - - // Check that super class name is valid class name - ObjCInterfaceDecl* SDecl = 0; - if (SuperClassname) { - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupInterfaceDecl(SuperClassname); - if (PrevDecl && !isa(PrevDecl)) { - Diag(SuperClassLoc, diag::err_redefinition_different_kind, - SuperClassname->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - else { - SDecl = dyn_cast_or_null(PrevDecl); - if (!SDecl) - Diag(SuperClassLoc, diag::err_undef_superclass, - SuperClassname->getName(), ClassName->getName()); - else if (IDecl && IDecl->getSuperClass() != SDecl) { - // This implementation and its interface do not have the same - // super class. - Diag(SuperClassLoc, diag::err_conflicting_super_class, - SDecl->getName()); - Diag(SDecl->getLocation(), diag::err_previous_definition); - } - } - } - - if (!IDecl) { - // Legacy case of @implementation with no corresponding @interface. - // Build, chain & install the interface decl into the identifier. - IDecl = new ObjCInterfaceDecl(AtClassImplLoc, 0, ClassName, - false, true); - IDecl->setNext(ClassName->getFETokenInfo()); - ClassName->setFETokenInfo(IDecl); - IDecl->setSuperClass(SDecl); - IDecl->setLocEnd(ClassLoc); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IDecl); - } - - ObjCImplementationDecl* IMPDecl = - new ObjCImplementationDecl(AtClassImplLoc, ClassName, IDecl, SDecl); - - // Check that there is no duplicate implementation of this class. - if (ObjCImplementations[ClassName]) - Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName()); - else // add it to the list. - ObjCImplementations[ClassName] = IMPDecl; - return IMPDecl; -} - -void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, - ObjCIvarDecl **ivars, unsigned numIvars, - SourceLocation RBrace) { - assert(ImpDecl && "missing implementation decl"); - ObjCInterfaceDecl* IDecl = getObjCInterfaceDecl(ImpDecl->getIdentifier()); - if (!IDecl) - return; - /// Check case of non-existing @interface decl. - /// (legacy objective-c @implementation decl without an @interface decl). - /// Add implementations's ivar to the synthesize class's ivar list. - if (IDecl->ImplicitInterfaceDecl()) { - IDecl->addInstanceVariablesToClass(ivars, numIvars, RBrace); - return; - } - // If implementation has empty ivar list, just return. - if (numIvars == 0) - return; - - assert(ivars && "missing @implementation ivars"); - - // Check interface's Ivar list against those in the implementation. - // names and types must match. - // - unsigned j = 0; - ObjCInterfaceDecl::ivar_iterator - IVI = IDecl->ivar_begin(), IVE = IDecl->ivar_end(); - for (; numIvars > 0 && IVI != IVE; ++IVI) { - ObjCIvarDecl* ImplIvar = ivars[j++]; - ObjCIvarDecl* ClsIvar = *IVI; - assert (ImplIvar && "missing implementation ivar"); - assert (ClsIvar && "missing class ivar"); - if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) { - Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type, - ImplIvar->getIdentifier()->getName()); - Diag(ClsIvar->getLocation(), diag::err_previous_definition, - ClsIvar->getIdentifier()->getName()); - } - // TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed - // as error. - else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { - Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name, - ImplIvar->getIdentifier()->getName()); - Diag(ClsIvar->getLocation(), diag::err_previous_definition, - ClsIvar->getIdentifier()->getName()); - return; - } - --numIvars; - } - - if (numIvars > 0) - Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count); - else if (IVI != IVE) - Diag((*IVI)->getLocation(), diag::err_inconsistant_ivar_count); -} - -void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl) { - if (!IncompleteImpl) { - Diag(ImpLoc, diag::warn_incomplete_impl); - IncompleteImpl = true; - } - Diag(ImpLoc, diag::warn_undef_method_impl, method->getSelector().getName()); -} - -/// CheckProtocolMethodDefs - This routine checks unimplemented methods -/// Declared in protocol, and those referenced by it. -void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, - ObjCProtocolDecl *PDecl, - bool& IncompleteImpl, - const llvm::DenseSet &InsMap, - const llvm::DenseSet &ClsMap) { - // check unimplemented instance methods. - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), - E = PDecl->instmeth_end(); I != E; ++I) { - ObjCMethodDecl *method = *I; - if (!InsMap.count(method->getSelector()) && - method->getImplementationControl() != ObjCMethodDecl::Optional) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); - } - // check unimplemented class methods - for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), - E = PDecl->classmeth_end(); I != E; ++I) { - ObjCMethodDecl *method = *I; - if (!ClsMap.count(method->getSelector()) && - method->getImplementationControl() != ObjCMethodDecl::Optional) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); - } - // Check on this protocols's referenced protocols, recursively - ObjCProtocolDecl** RefPDecl = PDecl->getReferencedProtocols(); - for (unsigned i = 0; i < PDecl->getNumReferencedProtocols(); i++) - CheckProtocolMethodDefs(ImpLoc, RefPDecl[i], IncompleteImpl, InsMap, ClsMap); -} - -void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, - ObjCInterfaceDecl* IDecl) { - llvm::DenseSet InsMap; - // Check and see if instance methods in class interface have been - // implemented in the implementation class. - for (ObjCImplementationDecl::instmeth_iterator I = IMPDecl->instmeth_begin(), - E = IMPDecl->instmeth_end(); I != E; ++I) - InsMap.insert((*I)->getSelector()); - - bool IncompleteImpl = false; - for (ObjCInterfaceDecl::instmeth_iterator I = IDecl->instmeth_begin(), - E = IDecl->instmeth_end(); I != E; ++I) - if (!InsMap.count((*I)->getSelector())) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); - - llvm::DenseSet ClsMap; - // Check and see if class methods in class interface have been - // implemented in the implementation class. - for (ObjCImplementationDecl::classmeth_iterator I =IMPDecl->classmeth_begin(), - E = IMPDecl->classmeth_end(); I != E; ++I) - ClsMap.insert((*I)->getSelector()); - - for (ObjCInterfaceDecl::classmeth_iterator I = IDecl->classmeth_begin(), - E = IDecl->classmeth_end(); I != E; ++I) - if (!ClsMap.count((*I)->getSelector())) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); - - // Check the protocol list for unimplemented methods in the @implementation - // class. - ObjCProtocolDecl** protocols = IDecl->getReferencedProtocols(); - for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) - CheckProtocolMethodDefs(IMPDecl->getLocation(), protocols[i], - IncompleteImpl, InsMap, ClsMap); -} - -/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the -/// category interface is implemented in the category @implementation. -void Sema::ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl, - ObjCCategoryDecl *CatClassDecl) { - llvm::DenseSet InsMap; - // Check and see if instance methods in category interface have been - // implemented in its implementation class. - for (ObjCCategoryImplDecl::instmeth_iterator I =CatImplDecl->instmeth_begin(), - E = CatImplDecl->instmeth_end(); I != E; ++I) - InsMap.insert((*I)->getSelector()); - - bool IncompleteImpl = false; - for (ObjCCategoryDecl::instmeth_iterator I = CatClassDecl->instmeth_begin(), - E = CatClassDecl->instmeth_end(); I != E; ++I) - if (!InsMap.count((*I)->getSelector())) - WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl); - - llvm::DenseSet ClsMap; - // Check and see if class methods in category interface have been - // implemented in its implementation class. - for (ObjCCategoryImplDecl::classmeth_iterator - I = CatImplDecl->classmeth_begin(), E = CatImplDecl->classmeth_end(); - I != E; ++I) - ClsMap.insert((*I)->getSelector()); - - for (ObjCCategoryDecl::classmeth_iterator I = CatClassDecl->classmeth_begin(), - E = CatClassDecl->classmeth_end(); I != E; ++I) - if (!ClsMap.count((*I)->getSelector())) - WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl); - - // Check the protocol list for unimplemented methods in the @implementation - // class. - ObjCProtocolDecl** protocols = CatClassDecl->getReferencedProtocols(); - for (unsigned i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) { - ObjCProtocolDecl* PDecl = protocols[i]; - CheckProtocolMethodDefs(CatImplDecl->getLocation(), PDecl, IncompleteImpl, - InsMap, ClsMap); - } -} - -/// ActOnForwardClassDeclaration - -Action::DeclTy * -Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, - IdentifierInfo **IdentList, unsigned NumElts) -{ - llvm::SmallVector Interfaces; - - for (unsigned i = 0; i != NumElts; ++i) { - // Check for another declaration kind with the same name. - ScopedDecl *PrevDecl = LookupInterfaceDecl(IdentList[i]); - if (PrevDecl && !isa(PrevDecl)) { - Diag(AtClassLoc, diag::err_redefinition_different_kind, - IdentList[i]->getName()); - Diag(PrevDecl->getLocation(), diag::err_previous_definition); - } - ObjCInterfaceDecl *IDecl = dyn_cast_or_null(PrevDecl); - if (!IDecl) { // Not already seen? Make a forward decl. - IDecl = new ObjCInterfaceDecl(AtClassLoc, 0, IdentList[i], true); - // Chain & install the interface decl into the identifier. - IDecl->setNext(IdentList[i]->getFETokenInfo()); - IdentList[i]->setFETokenInfo(IDecl); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(IDecl); - } - - Interfaces.push_back(IDecl); - } - - return new ObjCClassDecl(AtClassLoc, &Interfaces[0], Interfaces.size()); -} - - -/// MatchTwoMethodDeclarations - Checks that two methods have matching type and -/// returns true, or false, accordingly. -/// TODO: Handle protocol list; such as id in type comparisons -bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, - const ObjCMethodDecl *PrevMethod) { - if (Method->getResultType().getCanonicalType() != - PrevMethod->getResultType().getCanonicalType()) - return false; - for (int i = 0; i < Method->getNumParams(); i++) { - ParmVarDecl *ParamDecl = Method->getParamDecl(i); - ParmVarDecl *PrevParamDecl = PrevMethod->getParamDecl(i); - if (ParamDecl->getCanonicalType() != PrevParamDecl->getCanonicalType()) - return false; - } - return true; -} - -void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { - ObjCMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()]; - if (!FirstMethod.Method) { - // Haven't seen a method with this selector name yet - add it. - FirstMethod.Method = Method; - FirstMethod.Next = 0; - } else { - // We've seen a method with this name, now check the type signature(s). - bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); - - for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; - Next = Next->Next) - match = MatchTwoMethodDeclarations(Method, Next->Method); - - if (!match) { - // We have a new signature for an existing method - add it. - // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next); - FirstMethod.Next = OMI; - } - } -} - -void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { - ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()]; - if (!FirstMethod.Method) { - // Haven't seen a method with this selector name yet - add it. - FirstMethod.Method = Method; - FirstMethod.Next = 0; - } else { - // We've seen a method with this name, now check the type signature(s). - bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); - - for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; - Next = Next->Next) - match = MatchTwoMethodDeclarations(Method, Next->Method); - - if (!match) { - // We have a new signature for an existing method - add it. - // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next); - FirstMethod.Next = OMI; - } - } -} - -// Note: For class/category implemenations, allMethods/allProperties is -// always null. -void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, - DeclTy **allMethods, unsigned allNum, - DeclTy **allProperties, unsigned pNum) { - Decl *ClassDecl = static_cast(classDecl); - - // FIXME: If we don't have a ClassDecl, we have an error. We should consider - // always passing in a decl. If the decl has an error, isInvalidDecl() - // should be true. - if (!ClassDecl) - return; - - llvm::SmallVector insMethods; - llvm::SmallVector clsMethods; - - llvm::DenseMap InsMap; - llvm::DenseMap ClsMap; - - bool isInterfaceDeclKind = - (isa(ClassDecl) || isa(ClassDecl) - || isa(ClassDecl)); - bool checkIdenticalMethods = isa(ClassDecl); - - // TODO: property declaration in category and protocols. - if (pNum != 0 && isa(ClassDecl)) { - ObjCPropertyDecl **properties = new ObjCPropertyDecl*[pNum]; - memcpy(properties, allProperties, pNum*sizeof(ObjCPropertyDecl*)); - dyn_cast(ClassDecl)->setPropertyDecls(properties); - dyn_cast(ClassDecl)->setNumPropertyDecl(pNum); - } - - for (unsigned i = 0; i < allNum; i++ ) { - ObjCMethodDecl *Method = - cast_or_null(static_cast(allMethods[i])); - - if (!Method) continue; // Already issued a diagnostic. - if (Method->isInstance()) { - /// Check for instance method of the same name with incompatible types - const ObjCMethodDecl *&PrevMethod = InsMap[Method->getSelector()]; - bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) - : false; - if (isInterfaceDeclKind && PrevMethod && !match - || checkIdenticalMethods && match) { - Diag(Method->getLocation(), diag::error_duplicate_method_decl, - Method->getSelector().getName()); - Diag(PrevMethod->getLocation(), diag::err_previous_declaration); - } else { - insMethods.push_back(Method); - InsMap[Method->getSelector()] = Method; - /// The following allows us to typecheck messages to "id". - AddInstanceMethodToGlobalPool(Method); - } - } - else { - /// Check for class method of the same name with incompatible types - const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()]; - bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) - : false; - if (isInterfaceDeclKind && PrevMethod && !match - || checkIdenticalMethods && match) { - Diag(Method->getLocation(), diag::error_duplicate_method_decl, - Method->getSelector().getName()); - Diag(PrevMethod->getLocation(), diag::err_previous_declaration); - } else { - clsMethods.push_back(Method); - ClsMap[Method->getSelector()] = Method; - /// The following allows us to typecheck messages to "Class". - AddFactoryMethodToGlobalPool(Method); - } - } - } - - if (ObjCInterfaceDecl *I = dyn_cast(ClassDecl)) { - I->addMethods(&insMethods[0], insMethods.size(), - &clsMethods[0], clsMethods.size(), AtEndLoc); - } else if (ObjCProtocolDecl *P = dyn_cast(ClassDecl)) { - P->addMethods(&insMethods[0], insMethods.size(), - &clsMethods[0], clsMethods.size(), AtEndLoc); - } - else if (ObjCCategoryDecl *C = dyn_cast(ClassDecl)) { - C->addMethods(&insMethods[0], insMethods.size(), - &clsMethods[0], clsMethods.size(), AtEndLoc); - } - else if (ObjCImplementationDecl *IC = - dyn_cast(ClassDecl)) { - IC->setLocEnd(AtEndLoc); - if (ObjCInterfaceDecl* IDecl = getObjCInterfaceDecl(IC->getIdentifier())) - ImplMethodsVsClassMethods(IC, IDecl); - } else { - ObjCCategoryImplDecl* CatImplClass = cast(ClassDecl); - CatImplClass->setLocEnd(AtEndLoc); - ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface(); - // Find category interface decl and then check that all methods declared - // in this interface is implemented in the category @implementation. - if (IDecl) { - for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); - Categories; Categories = Categories->getNextClassCategory()) { - if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { - ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories); - break; - } - } - } - } -} - - -/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for -/// objective-c's type qualifier from the parser version of the same info. -static Decl::ObjCDeclQualifier -CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { - Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None; - if (PQTVal & ObjCDeclSpec::DQ_In) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_In); - if (PQTVal & ObjCDeclSpec::DQ_Inout) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Inout); - if (PQTVal & ObjCDeclSpec::DQ_Out) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Out); - if (PQTVal & ObjCDeclSpec::DQ_Bycopy) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy); - if (PQTVal & ObjCDeclSpec::DQ_Byref) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Byref); - if (PQTVal & ObjCDeclSpec::DQ_Oneway) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Oneway); - - return ret; -} - -Sema::DeclTy *Sema::ActOnMethodDeclaration( - SourceLocation MethodLoc, SourceLocation EndLoc, - tok::TokenKind MethodType, DeclTy *ClassDecl, - ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, - Selector Sel, - // optional arguments. The number of types/arguments is obtained - // from the Sel.getNumArgs(). - ObjCDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames, - AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, - bool isVariadic) { - - // Make sure we can establish a context for the method. - if (!ClassDecl) { - Diag(MethodLoc, diag::error_missing_method_context); - return 0; - } - llvm::SmallVector Params; - - for (unsigned i = 0; i < Sel.getNumArgs(); i++) { - // FIXME: arg->AttrList must be stored too! - QualType argType; - - if (ArgTypes[i]) - argType = QualType::getFromOpaquePtr(ArgTypes[i]); - else - argType = Context.getObjCIdType(); - ParmVarDecl* Param = ParmVarDecl::Create(Context, SourceLocation(/*FIXME*/), - ArgNames[i], argType, - VarDecl::None, 0); - Param->setObjCDeclQualifier( - CvtQTToAstBitMask(ArgQT[i].getObjCDeclQualifier())); - Params.push_back(Param); - } - QualType resultDeclType; - - if (ReturnType) - resultDeclType = QualType::getFromOpaquePtr(ReturnType); - else // get the type for "id". - resultDeclType = Context.getObjCIdType(); - - Decl *CDecl = static_cast(ClassDecl); - ObjCMethodDecl* ObjCMethod = new ObjCMethodDecl(MethodLoc, EndLoc, Sel, - resultDeclType, - CDecl, - 0, -1, AttrList, - MethodType == tok::minus, isVariadic, - MethodDeclKind == tok::objc_optional ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); - ObjCMethod->setMethodParams(&Params[0], Sel.getNumArgs()); - ObjCMethod->setObjCDeclQualifier( - CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); - const ObjCMethodDecl *PrevMethod = 0; - - // For implementations (which can be very "coarse grain"), we add the - // method now. This allows the AST to implement lookup methods that work - // incrementally (without waiting until we parse the @end). It also allows - // us to flag multiple declaration errors as they occur. - if (ObjCImplementationDecl *ImpDecl = - dyn_cast(CDecl)) { - if (MethodType == tok::minus) { - PrevMethod = ImpDecl->getInstanceMethod(Sel); - ImpDecl->addInstanceMethod(ObjCMethod); - } else { - PrevMethod = ImpDecl->getClassMethod(Sel); - ImpDecl->addClassMethod(ObjCMethod); - } - } - else if (ObjCCategoryImplDecl *CatImpDecl = - dyn_cast(CDecl)) { - if (MethodType == tok::minus) { - PrevMethod = CatImpDecl->getInstanceMethod(Sel); - CatImpDecl->addInstanceMethod(ObjCMethod); - } else { - PrevMethod = CatImpDecl->getClassMethod(Sel); - CatImpDecl->addClassMethod(ObjCMethod); - } - } - if (PrevMethod) { - // You can never have two method definitions with the same name. - Diag(ObjCMethod->getLocation(), diag::error_duplicate_method_decl, - ObjCMethod->getSelector().getName()); - Diag(PrevMethod->getLocation(), diag::err_previous_declaration); - } - return ObjCMethod; -} - -Sema::DeclTy *Sema::ActOnAddObjCProperties(SourceLocation AtLoc, - DeclTy **allProperties, unsigned NumProperties, ObjCDeclSpec &DS) { - ObjCPropertyDecl *PDecl = new ObjCPropertyDecl(AtLoc); - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readonly) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_getter) { - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); - PDecl->setGetterName(DS.getGetterName()); - } - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_setter) { - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); - PDecl->setSetterName(DS.getSetterName()); - } - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_assign) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readwrite) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_retain) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_copy) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - - if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - - PDecl->setNumPropertyDecls(NumProperties); - if (NumProperties != 0) { - ObjCIvarDecl **properties = new ObjCIvarDecl*[NumProperties]; - memcpy(properties, allProperties, NumProperties*sizeof(ObjCIvarDecl*)); - PDecl->setPropertyDecls(properties); - } - return PDecl; -} - diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp deleted file mode 100644 index d756345c1a8..00000000000 --- a/clang/Sema/SemaExpr.cpp +++ /dev/null @@ -1,2286 +0,0 @@ -//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for expressions. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "SemaUtil.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Expr.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/LiteralSupport.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -using namespace clang; - -/// ActOnStringLiteral - The specified tokens were lexed as pasted string -/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string -/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from -/// multiple tokens. However, the common case is that StringToks points to one -/// string. -/// -Action::ExprResult -Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { - assert(NumStringToks && "Must have at least one string!"); - - StringLiteralParser Literal(StringToks, NumStringToks, PP, Context.Target); - if (Literal.hadError) - return ExprResult(true); - - llvm::SmallVector StringTokLocs; - for (unsigned i = 0; i != NumStringToks; ++i) - StringTokLocs.push_back(StringToks[i].getLocation()); - - // Verify that pascal strings aren't too large. - if (Literal.Pascal && Literal.GetStringLength() > 256) - return Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long, - SourceRange(StringToks[0].getLocation(), - StringToks[NumStringToks-1].getLocation())); - - QualType StrTy = Context.CharTy; - // FIXME: handle wchar_t - if (Literal.Pascal) StrTy = Context.UnsignedCharTy; - - // Get an array type for the string, according to C99 6.4.5. This includes - // the nul terminator character as well as the string length for pascal - // strings. - StrTy = Context.getConstantArrayType(StrTy, - llvm::APInt(32, Literal.GetStringLength()+1), - ArrayType::Normal, 0); - - // Pass &StringTokLocs[0], StringTokLocs.size() to factory! - return new StringLiteral(Literal.GetString(), Literal.GetStringLength(), - Literal.AnyWide, StrTy, - StringToks[0].getLocation(), - StringToks[NumStringToks-1].getLocation()); -} - - -/// ActOnIdentifierExpr - The parser read an identifier in expression context, -/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this -/// identifier is used in an function call context. -Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen) { - // Could be enum-constant or decl. - ScopedDecl *D = LookupScopedDecl(&II, Decl::IDNS_Ordinary, Loc, S); - if (D == 0) { - // Otherwise, this could be an implicitly declared function reference (legal - // in C90, extension in C99). - if (HasTrailingLParen && - // Not in C++. - !getLangOptions().CPlusPlus) - D = ImplicitlyDefineFunction(Loc, II, S); - else { - if (CurMethodDecl) { - ObjCInterfaceDecl *IFace = CurMethodDecl->getClassInterface(); - ObjCInterfaceDecl *clsDeclared; - if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&II, clsDeclared)) { - IdentifierInfo &II = Context.Idents.get("self"); - ExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false); - return new ObjCIvarRefExpr(IV, IV->getType(), Loc, - static_cast(SelfExpr.Val), true, true); - } - } - // If this name wasn't predeclared and if this is not a function call, - // diagnose the problem. - return Diag(Loc, diag::err_undeclared_var_use, II.getName()); - } - } - if (ValueDecl *VD = dyn_cast(D)) { - // check if referencing an identifier with __attribute__((deprecated)). - if (VD->getAttr()) - Diag(Loc, diag::warn_deprecated, VD->getName()); - - // Only create DeclRefExpr's for valid Decl's. - if (VD->isInvalidDecl()) - return true; - return new DeclRefExpr(VD, VD->getType(), Loc); - } - if (isa(D)) - return Diag(Loc, diag::err_unexpected_typedef, II.getName()); - if (isa(D)) - return Diag(Loc, diag::err_unexpected_interface, II.getName()); - - assert(0 && "Invalid decl"); - abort(); -} - -Sema::ExprResult Sema::ActOnPreDefinedExpr(SourceLocation Loc, - tok::TokenKind Kind) { - PreDefinedExpr::IdentType IT; - - switch (Kind) { - default: assert(0 && "Unknown simple primary expr!"); - case tok::kw___func__: IT = PreDefinedExpr::Func; break; // [C99 6.4.2.2] - case tok::kw___FUNCTION__: IT = PreDefinedExpr::Function; break; - case tok::kw___PRETTY_FUNCTION__: IT = PreDefinedExpr::PrettyFunction; break; - } - - // Verify that this is in a function context. - if (CurFunctionDecl == 0 && CurMethodDecl == 0) - return Diag(Loc, diag::err_predef_outside_function); - - // Pre-defined identifiers are of type char[x], where x is the length of the - // string. - unsigned Length; - if (CurFunctionDecl) - Length = CurFunctionDecl->getIdentifier()->getLength(); - else - Length = CurMethodDecl->getSynthesizedMethodSize(); - - llvm::APInt LengthI(32, Length + 1); - QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const); - ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); - return new PreDefinedExpr(Loc, ResTy, IT); -} - -Sema::ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { - llvm::SmallString<16> CharBuffer; - CharBuffer.resize(Tok.getLength()); - const char *ThisTokBegin = &CharBuffer[0]; - unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); - - CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - Tok.getLocation(), PP); - if (Literal.hadError()) - return ExprResult(true); - - QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy; - - return new CharacterLiteral(Literal.getValue(), type, Tok.getLocation()); -} - -Action::ExprResult Sema::ActOnNumericConstant(const Token &Tok) { - // fast path for a single digit (which is quite common). A single digit - // cannot have a trigraph, escaped newline, radix prefix, or type suffix. - if (Tok.getLength() == 1) { - const char *t = PP.getSourceManager().getCharacterData(Tok.getLocation()); - - unsigned IntSize =static_cast(Context.getTypeSize(Context.IntTy)); - return ExprResult(new IntegerLiteral(llvm::APInt(IntSize, *t-'0'), - Context.IntTy, - Tok.getLocation())); - } - llvm::SmallString<512> IntegerBuffer; - IntegerBuffer.resize(Tok.getLength()); - const char *ThisTokBegin = &IntegerBuffer[0]; - - // Get the spelling of the token, which eliminates trigraphs, etc. - unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); - NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - Tok.getLocation(), PP); - if (Literal.hadError) - return ExprResult(true); - - Expr *Res; - - if (Literal.isFloatingLiteral()) { - QualType Ty; - const llvm::fltSemantics *Format; - - if (Literal.isFloat) { - Ty = Context.FloatTy; - Format = Context.Target.getFloatFormat(); - } else if (!Literal.isLong) { - Ty = Context.DoubleTy; - Format = Context.Target.getDoubleFormat(); - } else { - Ty = Context.LongDoubleTy; - Format = Context.Target.getLongDoubleFormat(); - } - - // isExact will be set by GetFloatValue(). - bool isExact = false; - - Res = new FloatingLiteral(Literal.GetFloatValue(*Format,&isExact), &isExact, - Ty, Tok.getLocation()); - - } else if (!Literal.isIntegerLiteral()) { - return ExprResult(true); - } else { - QualType t; - - // long long is a C99 feature. - if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && - Literal.isLongLong) - Diag(Tok.getLocation(), diag::ext_longlong); - - // Get the value in the widest-possible width. - llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0); - - if (Literal.GetIntegerValue(ResultVal)) { - // If this value didn't fit into uintmax_t, warn and force to ull. - Diag(Tok.getLocation(), diag::warn_integer_too_large); - t = Context.UnsignedLongLongTy; - assert(Context.getTypeSize(t) == ResultVal.getBitWidth() && - "long long is not intmax_t?"); - } else { - // If this value fits into a ULL, try to figure out what else it fits into - // according to the rules of C99 6.4.4.1p5. - - // Octal, Hexadecimal, and integers with a U suffix are allowed to - // be an unsigned int. - bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10; - - // Check from smallest to largest, picking the smallest type we can. - if (!Literal.isLong && !Literal.isLongLong) { - // Are int/unsigned possibilities? - unsigned IntSize = - static_cast(Context.getTypeSize(Context.IntTy)); - // Does it fit in a unsigned int? - if (ResultVal.isIntN(IntSize)) { - // Does it fit in a signed int? - if (!Literal.isUnsigned && ResultVal[IntSize-1] == 0) - t = Context.IntTy; - else if (AllowUnsigned) - t = Context.UnsignedIntTy; - } - - if (!t.isNull()) - ResultVal.trunc(IntSize); - } - - // Are long/unsigned long possibilities? - if (t.isNull() && !Literal.isLongLong) { - unsigned LongSize = - static_cast(Context.getTypeSize(Context.LongTy)); - - // Does it fit in a unsigned long? - if (ResultVal.isIntN(LongSize)) { - // Does it fit in a signed long? - if (!Literal.isUnsigned && ResultVal[LongSize-1] == 0) - t = Context.LongTy; - else if (AllowUnsigned) - t = Context.UnsignedLongTy; - } - if (!t.isNull()) - ResultVal.trunc(LongSize); - } - - // Finally, check long long if needed. - if (t.isNull()) { - unsigned LongLongSize = - static_cast(Context.getTypeSize(Context.LongLongTy)); - - // Does it fit in a unsigned long long? - if (ResultVal.isIntN(LongLongSize)) { - // Does it fit in a signed long long? - if (!Literal.isUnsigned && ResultVal[LongLongSize-1] == 0) - t = Context.LongLongTy; - else if (AllowUnsigned) - t = Context.UnsignedLongLongTy; - } - } - - // If we still couldn't decide a type, we probably have something that - // does not fit in a signed long long, but has no U suffix. - if (t.isNull()) { - Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed); - t = Context.UnsignedLongLongTy; - } - } - - Res = new IntegerLiteral(ResultVal, t, Tok.getLocation()); - } - - // If this is an imaginary literal, create the ImaginaryLiteral wrapper. - if (Literal.isImaginary) - Res = new ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); - - return Res; -} - -Action::ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, - ExprTy *Val) { - Expr *e = (Expr *)Val; - assert((e != 0) && "ActOnParenExpr() missing expr"); - return new ParenExpr(L, R, e); -} - -/// The UsualUnaryConversions() function is *not* called by this routine. -/// See C99 6.3.2.1p[2-4] for more details. -QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType, - SourceLocation OpLoc, bool isSizeof) { - // C99 6.5.3.4p1: - if (isa(exprType) && isSizeof) - // alignof(function) is allowed. - Diag(OpLoc, diag::ext_sizeof_function_type); - else if (exprType->isVoidType()) - Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof"); - else if (exprType->isIncompleteType()) { - Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : - diag::err_alignof_incomplete_type, - exprType.getAsString()); - return QualType(); // error - } - // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Context.getSizeType(); -} - -Action::ExprResult Sema:: -ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, - SourceLocation LPLoc, TypeTy *Ty, - SourceLocation RPLoc) { - // If error parsing type, ignore. - if (Ty == 0) return true; - - // Verify that this is a valid expression. - QualType ArgTy = QualType::getFromOpaquePtr(Ty); - - QualType resultType = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, isSizeof); - - if (resultType.isNull()) - return true; - return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, resultType, OpLoc, RPLoc); -} - -QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc) { - DefaultFunctionArrayConversion(V); - - // These operators return the element type of a complex type. - if (const ComplexType *CT = V->getType()->getAsComplexType()) - return CT->getElementType(); - - // Otherwise they pass through real integer and floating point types here. - if (V->getType()->isArithmeticType()) - return V->getType(); - - // Reject anything else. - Diag(Loc, diag::err_realimag_invalid_type, V->getType().getAsString()); - return QualType(); -} - - - -Action::ExprResult Sema::ActOnPostfixUnaryOp(SourceLocation OpLoc, - tok::TokenKind Kind, - ExprTy *Input) { - UnaryOperator::Opcode Opc; - switch (Kind) { - default: assert(0 && "Unknown unary op!"); - case tok::plusplus: Opc = UnaryOperator::PostInc; break; - case tok::minusminus: Opc = UnaryOperator::PostDec; break; - } - QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc); - if (result.isNull()) - return true; - return new UnaryOperator((Expr *)Input, Opc, result, OpLoc); -} - -Action::ExprResult Sema:: -ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, - ExprTy *Idx, SourceLocation RLoc) { - Expr *LHSExp = static_cast(Base), *RHSExp = static_cast(Idx); - - // Perform default conversions. - DefaultFunctionArrayConversion(LHSExp); - DefaultFunctionArrayConversion(RHSExp); - - QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); - - // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent - // to the expression *((e1)+(e2)). This means the array "Base" may actually be - // in the subscript position. As a result, we need to derive the array base - // and index from the expression types. - Expr *BaseExpr, *IndexExpr; - QualType ResultType; - if (const PointerType *PTy = LHSTy->getAsPointerType()) { - BaseExpr = LHSExp; - IndexExpr = RHSExp; - // FIXME: need to deal with const... - ResultType = PTy->getPointeeType(); - } else if (const PointerType *PTy = RHSTy->getAsPointerType()) { - // Handle the uncommon case of "123[Ptr]". - BaseExpr = RHSExp; - IndexExpr = LHSExp; - // FIXME: need to deal with const... - ResultType = PTy->getPointeeType(); - } else if (const VectorType *VTy = LHSTy->getAsVectorType()) { - BaseExpr = LHSExp; // vectors: V[123] - IndexExpr = RHSExp; - - // Component access limited to variables (reject vec4.rg[1]). - if (!isa(BaseExpr) && !isa(BaseExpr)) - return Diag(LLoc, diag::err_ocuvector_component_access, - SourceRange(LLoc, RLoc)); - // FIXME: need to deal with const... - ResultType = VTy->getElementType(); - } else { - return Diag(LHSExp->getLocStart(), diag::err_typecheck_subscript_value, - RHSExp->getSourceRange()); - } - // C99 6.5.2.1p1 - if (!IndexExpr->getType()->isIntegerType()) - return Diag(IndexExpr->getLocStart(), diag::err_typecheck_subscript, - IndexExpr->getSourceRange()); - - // C99 6.5.2.1p1: "shall have type "pointer to *object* type". In practice, - // the following check catches trying to index a pointer to a function (e.g. - // void (*)(int)). Functions are not objects in C99. - if (!ResultType->isObjectType()) - return Diag(BaseExpr->getLocStart(), - diag::err_typecheck_subscript_not_object, - BaseExpr->getType().getAsString(), BaseExpr->getSourceRange()); - - return new ArraySubscriptExpr(LHSExp, RHSExp, ResultType, RLoc); -} - -QualType Sema:: -CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc, - IdentifierInfo &CompName, SourceLocation CompLoc) { - const OCUVectorType *vecType = baseType->getAsOCUVectorType(); - - // The vector accessor can't exceed the number of elements. - const char *compStr = CompName.getName(); - if (strlen(compStr) > vecType->getNumElements()) { - Diag(OpLoc, diag::err_ocuvector_component_exceeds_length, - baseType.getAsString(), SourceRange(CompLoc)); - return QualType(); - } - // The component names must come from the same set. - if (vecType->getPointAccessorIdx(*compStr) != -1) { - do - compStr++; - while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1); - } else if (vecType->getColorAccessorIdx(*compStr) != -1) { - do - compStr++; - while (*compStr && vecType->getColorAccessorIdx(*compStr) != -1); - } else if (vecType->getTextureAccessorIdx(*compStr) != -1) { - do - compStr++; - while (*compStr && vecType->getTextureAccessorIdx(*compStr) != -1); - } - - if (*compStr) { - // We didn't get to the end of the string. This means the component names - // didn't come from the same set *or* we encountered an illegal name. - Diag(OpLoc, diag::err_ocuvector_component_name_illegal, - std::string(compStr,compStr+1), SourceRange(CompLoc)); - return QualType(); - } - // Each component accessor can't exceed the vector type. - compStr = CompName.getName(); - while (*compStr) { - if (vecType->isAccessorWithinNumElements(*compStr)) - compStr++; - else - break; - } - if (*compStr) { - // We didn't get to the end of the string. This means a component accessor - // exceeds the number of elements in the vector. - Diag(OpLoc, diag::err_ocuvector_component_exceeds_length, - baseType.getAsString(), SourceRange(CompLoc)); - return QualType(); - } - // The component accessor looks fine - now we need to compute the actual type. - // The vector type is implied by the component accessor. For example, - // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. - unsigned CompSize = strlen(CompName.getName()); - if (CompSize == 1) - return vecType->getElementType(); - - QualType VT = Context.getOCUVectorType(vecType->getElementType(), CompSize); - // Now look up the TypeDefDecl from the vector type. Without this, - // diagostics look bad. We want OCU vector types to appear built-in. - for (unsigned i = 0, e = OCUVectorDecls.size(); i != e; ++i) { - if (OCUVectorDecls[i]->getUnderlyingType() == VT) - return Context.getTypedefType(OCUVectorDecls[i]); - } - return VT; // should never get here (a typedef type should always be found). -} - -Action::ExprResult Sema:: -ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, - tok::TokenKind OpKind, SourceLocation MemberLoc, - IdentifierInfo &Member) { - Expr *BaseExpr = static_cast(Base); - assert(BaseExpr && "no record expression"); - - // Perform default conversions. - DefaultFunctionArrayConversion(BaseExpr); - - QualType BaseType = BaseExpr->getType(); - assert(!BaseType.isNull() && "no type for member expression"); - - if (OpKind == tok::arrow) { - if (const PointerType *PT = BaseType->getAsPointerType()) - BaseType = PT->getPointeeType(); - else - return Diag(OpLoc, diag::err_typecheck_member_reference_arrow, - SourceRange(MemberLoc)); - } - // The base type is either a record or an OCUVectorType. - if (const RecordType *RTy = BaseType->getAsRecordType()) { - RecordDecl *RDecl = RTy->getDecl(); - if (RTy->isIncompleteType()) - return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RDecl->getName(), - BaseExpr->getSourceRange()); - // The record definition is complete, now make sure the member is valid. - FieldDecl *MemberDecl = RDecl->getMember(&Member); - if (!MemberDecl) - return Diag(OpLoc, diag::err_typecheck_no_member, Member.getName(), - SourceRange(MemberLoc)); - - // Figure out the type of the member; see C99 6.5.2.3p3 - // FIXME: Handle address space modifiers - QualType MemberType = MemberDecl->getType(); - unsigned combinedQualifiers = - MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); - MemberType = MemberType.getQualifiedType(combinedQualifiers); - - return new MemberExpr(BaseExpr, OpKind==tok::arrow, MemberDecl, - MemberLoc, MemberType); - } else if (BaseType->isOCUVectorType() && OpKind == tok::period) { - // Component access limited to variables (reject vec4.rg.g). - if (!isa(BaseExpr)) - return Diag(OpLoc, diag::err_ocuvector_component_access, - SourceRange(MemberLoc)); - QualType ret = CheckOCUVectorComponent(BaseType, OpLoc, Member, MemberLoc); - if (ret.isNull()) - return true; - return new OCUVectorElementExpr(ret, BaseExpr, Member, MemberLoc); - } else if (BaseType->isObjCInterfaceType()) { - ObjCInterfaceDecl *IFace; - if (isa(BaseType.getCanonicalType())) - IFace = dyn_cast(BaseType)->getDecl(); - else - IFace = dyn_cast(BaseType)->getDecl(); - ObjCInterfaceDecl *clsDeclared; - if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&Member, clsDeclared)) - return new ObjCIvarRefExpr(IV, IV->getType(), MemberLoc, BaseExpr, - OpKind==tok::arrow); - } - return Diag(OpLoc, diag::err_typecheck_member_reference_structUnion, - SourceRange(MemberLoc)); -} - -/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. -/// This provides the location of the left/right parens and a list of comma -/// locations. -Action::ExprResult Sema:: -ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, - ExprTy **args, unsigned NumArgs, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { - Expr *Fn = static_cast(fn); - Expr **Args = reinterpret_cast(args); - assert(Fn && "no function call expression"); - - // Make the call expr early, before semantic checks. This guarantees cleanup - // of arguments and function on error. - llvm::OwningPtr TheCall(new CallExpr(Fn, Args, NumArgs, - Context.BoolTy, RParenLoc)); - - // Promote the function operand. - TheCall->setCallee(UsualUnaryConversions(Fn)); - - // C99 6.5.2.2p1 - "The expression that denotes the called function shall have - // type pointer to function". - const PointerType *PT = Fn->getType()->getAsPointerType(); - if (PT == 0) - return Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function, - SourceRange(Fn->getLocStart(), RParenLoc)); - const FunctionType *FuncT = PT->getPointeeType()->getAsFunctionType(); - if (FuncT == 0) - return Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function, - SourceRange(Fn->getLocStart(), RParenLoc)); - - // We know the result type of the call, set it. - TheCall->setType(FuncT->getResultType()); - - if (const FunctionTypeProto *Proto = dyn_cast(FuncT)) { - // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by - // assignment, to the types of the corresponding parameter, ... - unsigned NumArgsInProto = Proto->getNumArgs(); - unsigned NumArgsToCheck = NumArgs; - - // If too few arguments are available, don't make the call. - if (NumArgs < NumArgsInProto) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, - Fn->getSourceRange()); - - // If too many are passed and not variadic, error on the extras and drop - // them. - if (NumArgs > NumArgsInProto) { - if (!Proto->isVariadic()) { - Diag(Args[NumArgsInProto]->getLocStart(), - diag::err_typecheck_call_too_many_args, Fn->getSourceRange(), - SourceRange(Args[NumArgsInProto]->getLocStart(), - Args[NumArgs-1]->getLocEnd())); - // This deletes the extra arguments. - TheCall->setNumArgs(NumArgsInProto); - } - NumArgsToCheck = NumArgsInProto; - } - - // Continue to check argument types (even if we have too few/many args). - for (unsigned i = 0; i != NumArgsToCheck; i++) { - Expr *Arg = Args[i]; - QualType ProtoArgType = Proto->getArgType(i); - QualType ArgType = Arg->getType(); - - // Compute implicit casts from the operand to the formal argument type. - AssignConvertType ConvTy = - CheckSingleAssignmentConstraints(ProtoArgType, Arg); - TheCall->setArg(i, Arg); - - if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), ProtoArgType, - ArgType, Arg, "passing")) - return true; - } - - // If this is a variadic call, handle args passed through "...". - if (Proto->isVariadic()) { - // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = NumArgsInProto; i != NumArgs; i++) { - Expr *Arg = Args[i]; - DefaultArgumentPromotion(Arg); - TheCall->setArg(i, Arg); - } - } - } else { - assert(isa(FuncT) && "Unknown FunctionType!"); - - // Promote the arguments (C99 6.5.2.2p6). - for (unsigned i = 0; i != NumArgs; i++) { - Expr *Arg = Args[i]; - DefaultArgumentPromotion(Arg); - TheCall->setArg(i, Arg); - } - } - - // Do special checking on direct calls to functions. - if (ImplicitCastExpr *IcExpr = dyn_cast(Fn)) - if (DeclRefExpr *DRExpr = dyn_cast(IcExpr->getSubExpr())) - if (FunctionDecl *FDecl = dyn_cast(DRExpr->getDecl())) - if (CheckFunctionCall(FDecl, TheCall.get())) - return true; - - return TheCall.take(); -} - -Action::ExprResult Sema:: -ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprTy *InitExpr) { - assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); - QualType literalType = QualType::getFromOpaquePtr(Ty); - // FIXME: put back this assert when initializers are worked out. - //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); - Expr *literalExpr = static_cast(InitExpr); - - // FIXME: add more semantic analysis (C99 6.5.2.5). - if (CheckInitializerTypes(literalExpr, literalType)) - return true; - - bool isFileScope = !CurFunctionDecl && !CurMethodDecl; - if (isFileScope) { // 6.5.2.5p3 - if (CheckForConstantInitializer(literalExpr, literalType)) - return true; - } - return new CompoundLiteralExpr(LParenLoc, literalType, literalExpr, isFileScope); -} - -Action::ExprResult Sema:: -ActOnInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit, - SourceLocation RBraceLoc) { - Expr **InitList = reinterpret_cast(initlist); - - // Semantic analysis for initializers is done by ActOnDeclarator() and - // CheckInitializer() - it requires knowledge of the object being intialized. - - InitListExpr *e = new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc); - e->setType(Context.VoidTy); // FIXME: just a place holder for now. - return e; -} - -bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { - assert(VectorTy->isVectorType() && "Not a vector type!"); - - if (Ty->isVectorType() || Ty->isIntegerType()) { - if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty)) - return Diag(R.getBegin(), - Ty->isVectorType() ? - diag::err_invalid_conversion_between_vectors : - diag::err_invalid_conversion_between_vector_and_integer, - VectorTy.getAsString().c_str(), - Ty.getAsString().c_str(), R); - } else - return Diag(R.getBegin(), - diag::err_invalid_conversion_between_vector_and_scalar, - VectorTy.getAsString().c_str(), - Ty.getAsString().c_str(), R); - - return false; -} - -Action::ExprResult Sema:: -ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprTy *Op) { - assert((Ty != 0) && (Op != 0) && "ActOnCastExpr(): missing type or expr"); - - Expr *castExpr = static_cast(Op); - QualType castType = QualType::getFromOpaquePtr(Ty); - - UsualUnaryConversions(castExpr); - - // C99 6.5.4p2: the cast type needs to be void or scalar and the expression - // type needs to be scalar. - if (!castType->isVoidType()) { // Cast to void allows any expr type. - if (!castType->isScalarType() && !castType->isVectorType()) - return Diag(LParenLoc, diag::err_typecheck_cond_expect_scalar, - castType.getAsString(), SourceRange(LParenLoc, RParenLoc)); - if (!castExpr->getType()->isScalarType() && - !castExpr->getType()->isVectorType()) - return Diag(castExpr->getLocStart(), - diag::err_typecheck_expect_scalar_operand, - castExpr->getType().getAsString(),castExpr->getSourceRange()); - - if (castExpr->getType()->isVectorType()) { - if (CheckVectorCast(SourceRange(LParenLoc, RParenLoc), - castExpr->getType(), castType)) - return true; - } else if (castType->isVectorType()) { - if (CheckVectorCast(SourceRange(LParenLoc, RParenLoc), - castType, castExpr->getType())) - return true; - } - } - return new CastExpr(castType, castExpr, LParenLoc); -} - -/// Note that lex is not null here, even if this is the gnu "x ?: y" extension. -/// In that case, lex = cond. -inline QualType Sema::CheckConditionalOperands( // C99 6.5.15 - Expr *&cond, Expr *&lex, Expr *&rex, SourceLocation questionLoc) { - UsualUnaryConversions(cond); - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); - QualType condT = cond->getType(); - QualType lexT = lex->getType(); - QualType rexT = rex->getType(); - - // first, check the condition. - if (!condT->isScalarType()) { // C99 6.5.15p2 - Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar, - condT.getAsString()); - return QualType(); - } - - // Now check the two expressions. - - // If both operands have arithmetic type, do the usual arithmetic conversions - // to find a common type: C99 6.5.15p3,5. - if (lexT->isArithmeticType() && rexT->isArithmeticType()) { - UsualArithmeticConversions(lex, rex); - return lex->getType(); - } - - // If both operands are the same structure or union type, the result is that - // type. - if (const RecordType *LHSRT = lexT->getAsRecordType()) { // C99 6.5.15p3 - if (const RecordType *RHSRT = rexT->getAsRecordType()) - if (LHSRT->getDecl() == RHSRT->getDecl()) - // "If both the operands have structure or union type, the result has - // that type." This implies that CV qualifiers are dropped. - return lexT.getUnqualifiedType(); - } - - // C99 6.5.15p5: "If both operands have void type, the result has void type." - if (lexT->isVoidType() && rexT->isVoidType()) - return lexT.getUnqualifiedType(); - - // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has - // the type of the other operand." - if (lexT->isPointerType() && rex->isNullPointerConstant(Context)) { - ImpCastExprToType(rex, lexT); // promote the null to a pointer. - return lexT; - } - if (rexT->isPointerType() && lex->isNullPointerConstant(Context)) { - ImpCastExprToType(lex, rexT); // promote the null to a pointer. - return rexT; - } - // Handle the case where both operands are pointers before we handle null - // pointer constants in case both operands are null pointer constants. - if (const PointerType *LHSPT = lexT->getAsPointerType()) { // C99 6.5.15p3,6 - if (const PointerType *RHSPT = rexT->getAsPointerType()) { - // get the "pointed to" types - QualType lhptee = LHSPT->getPointeeType(); - QualType rhptee = RHSPT->getPointeeType(); - - // ignore qualifiers on void (C99 6.5.15p3, clause 6) - if (lhptee->isVoidType() && - (rhptee->isObjectType() || rhptee->isIncompleteType())) { - // Figure out necessary qualifiers (C99 6.5.15p6) - QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers()); - QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(lex, destType); // add qualifiers if necessary - ImpCastExprToType(rex, destType); // promote to void* - return destType; - } - if (rhptee->isVoidType() && - (lhptee->isObjectType() || lhptee->isIncompleteType())) { - QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers()); - QualType destType = Context.getPointerType(destPointee); - ImpCastExprToType(lex, destType); // add qualifiers if necessary - ImpCastExprToType(rex, destType); // promote to void* - return destType; - } - - if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) { - Diag(questionLoc, diag::warn_typecheck_cond_incompatible_pointers, - lexT.getAsString(), rexT.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - // In this situation, we assume void* type. No especially good - // reason, but this is what gcc does, and we do have to pick - // to get a consistent AST. - QualType voidPtrTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(lex, voidPtrTy); - ImpCastExprToType(rex, voidPtrTy); - return voidPtrTy; - } - // The pointer types are compatible. - // C99 6.5.15p6: If both operands are pointers to compatible types *or* to - // differently qualified versions of compatible types, the result type is - // a pointer to an appropriately qualified version of the *composite* - // type. - // FIXME: Need to return the composite type. - // FIXME: Need to add qualifiers - return lexT; - } - } - - // Otherwise, the operands are not compatible. - Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands, - lexT.getAsString(), rexT.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - return QualType(); -} - -/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null -/// in the case of a the GNU conditional expr extension. -Action::ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, - SourceLocation ColonLoc, - ExprTy *Cond, ExprTy *LHS, - ExprTy *RHS) { - Expr *CondExpr = (Expr *) Cond; - Expr *LHSExpr = (Expr *) LHS, *RHSExpr = (Expr *) RHS; - - // If this is the gnu "x ?: y" extension, analyze the types as though the LHS - // was the condition. - bool isLHSNull = LHSExpr == 0; - if (isLHSNull) - LHSExpr = CondExpr; - - QualType result = CheckConditionalOperands(CondExpr, LHSExpr, - RHSExpr, QuestionLoc); - if (result.isNull()) - return true; - return new ConditionalOperator(CondExpr, isLHSNull ? 0 : LHSExpr, - RHSExpr, result); -} - -/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that -/// do not have a prototype. Arguments that have type float are promoted to -/// double. All other argument types are converted by UsualUnaryConversions(). -void Sema::DefaultArgumentPromotion(Expr *&Expr) { - QualType Ty = Expr->getType(); - assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); - - if (Ty == Context.FloatTy) - ImpCastExprToType(Expr, Context.DoubleTy); - else - UsualUnaryConversions(Expr); -} - -/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). -void Sema::DefaultFunctionArrayConversion(Expr *&e) { - QualType t = e->getType(); - assert(!t.isNull() && "DefaultFunctionArrayConversion - missing type"); - - if (const ReferenceType *ref = t->getAsReferenceType()) { - ImpCastExprToType(e, ref->getReferenceeType()); // C++ [expr] - t = e->getType(); - } - if (t->isFunctionType()) - ImpCastExprToType(e, Context.getPointerType(t)); - else if (const ArrayType *ary = t->getAsArrayType()) { - // Make sure we don't lose qualifiers when dealing with typedefs. Example: - // typedef int arr[10]; - // void test2() { - // const arr b; - // b[4] = 1; - // } - QualType ELT = ary->getElementType(); - // FIXME: Handle ASQualType - ELT = ELT.getQualifiedType(t.getCVRQualifiers()|ELT.getCVRQualifiers()); - ImpCastExprToType(e, Context.getPointerType(ELT)); - } -} - -/// UsualUnaryConversions - Performs various conversions that are common to most -/// operators (C99 6.3). The conversions of array and function types are -/// sometimes surpressed. For example, the array->pointer conversion doesn't -/// apply if the array is an argument to the sizeof or address (&) operators. -/// In these instances, this routine should *not* be called. -Expr *Sema::UsualUnaryConversions(Expr *&Expr) { - QualType Ty = Expr->getType(); - assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - - if (const ReferenceType *Ref = Ty->getAsReferenceType()) { - ImpCastExprToType(Expr, Ref->getReferenceeType()); // C++ [expr] - Ty = Expr->getType(); - } - if (Ty->isPromotableIntegerType()) // C99 6.3.1.1p2 - ImpCastExprToType(Expr, Context.IntTy); - else - DefaultFunctionArrayConversion(Expr); - - return Expr; -} - -/// UsualArithmeticConversions - Performs various conversions that are common to -/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this -/// routine returns the first non-arithmetic type found. The client is -/// responsible for emitting appropriate error diagnostics. -/// FIXME: verify the conversion rules for "complex int" are consistent with GCC. -QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, - bool isCompAssign) { - if (!isCompAssign) { - UsualUnaryConversions(lhsExpr); - UsualUnaryConversions(rhsExpr); - } - // For conversion purposes, we ignore any qualifiers. - // For example, "const float" and "float" are equivalent. - QualType lhs = lhsExpr->getType().getCanonicalType().getUnqualifiedType(); - QualType rhs = rhsExpr->getType().getCanonicalType().getUnqualifiedType(); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // If either side is a non-arithmetic type (e.g. a pointer), we are done. - // The caller can deal with this (e.g. pointer + int). - if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return lhs; - - // At this point, we have two different arithmetic types. - - // Handle complex types first (C99 6.3.1.8p1). - if (lhs->isComplexType() || rhs->isComplexType()) { - // if we have an integer operand, the result is the complex type. - if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { - // convert the rhs to the lhs complex type. - if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); - return lhs; - } - if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { - // convert the lhs to the rhs complex type. - if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); - return rhs; - } - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - int result = Context.compareFloatingType(lhs, rhs); - - if (result > 0) { // The left side is bigger, convert rhs. - rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs); - if (!isCompAssign) - ImpCastExprToType(rhsExpr, rhs); - } else if (result < 0) { // The right side is bigger, convert lhs. - lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs); - if (!isCompAssign) - ImpCastExprToType(lhsExpr, lhs); - } - // At this point, lhs and rhs have the same rank/size. Now, make sure the - // domains match. This is a requirement for our implementation, C99 - // does not require this promotion. - if (lhs != rhs) { // Domains don't match, we have complex/float mix. - if (lhs->isRealFloatingType()) { // handle "double, _Complex double". - if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs); - return rhs; - } else { // handle "_Complex double, double". - if (!isCompAssign) - ImpCastExprToType(rhsExpr, lhs); - return lhs; - } - } - return lhs; // The domain/size match exactly. - } - // Now handle "real" floating types (i.e. float, double, long double). - if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { - // if we have an integer operand, the result is the real floating type. - if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { - // convert rhs to the lhs floating point type. - if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); - return lhs; - } - if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { - // convert lhs to the rhs floating point type. - if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); - return rhs; - } - // We have two real floating types, float/complex combos were handled above. - // Convert the smaller operand to the bigger result. - int result = Context.compareFloatingType(lhs, rhs); - - if (result > 0) { // convert the rhs - if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); - return lhs; - } - if (result < 0) { // convert the lhs - if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs - return rhs; - } - assert(0 && "Sema::UsualArithmeticConversions(): illegal float comparison"); - } - if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { - // Handle GCC complex int extension. - const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); - const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); - - if (lhsComplexInt && rhsComplexInt) { - if (Context.maxIntegerType(lhsComplexInt->getElementType(), - rhsComplexInt->getElementType()) == lhs) { - // convert the rhs - if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); - return lhs; - } - if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs); // convert the lhs - return rhs; - } else if (lhsComplexInt && rhs->isIntegerType()) { - // convert the rhs to the lhs complex type. - if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); - return lhs; - } else if (rhsComplexInt && lhs->isIntegerType()) { - // convert the lhs to the rhs complex type. - if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); - return rhs; - } - } - // Finally, we have two differing integer types. - if (Context.maxIntegerType(lhs, rhs) == lhs) { // convert the rhs - if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); - return lhs; - } - if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs - return rhs; -} - -// CheckPointerTypesForAssignment - This is a very tricky routine (despite -// being closely modeled after the C99 spec:-). The odd characteristic of this -// routine is it effectively iqnores the qualifiers on the top level pointee. -// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. -// FIXME: add a couple examples in this comment. -Sema::AssignConvertType -Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { - QualType lhptee, rhptee; - - // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = lhsType->getAsPointerType()->getPointeeType(); - rhptee = rhsType->getAsPointerType()->getPointeeType(); - - // make sure we operate on the canonical type - lhptee = lhptee.getCanonicalType(); - rhptee = rhptee.getCanonicalType(); - - AssignConvertType ConvTy = Compatible; - - // C99 6.5.16.1p1: This following citation is common to constraints - // 3 & 4 (below). ...and the type *pointed to* by the left has all the - // qualifiers of the type *pointed to* by the right; - // FIXME: Handle ASQualType - if ((lhptee.getCVRQualifiers() & rhptee.getCVRQualifiers()) != - rhptee.getCVRQualifiers()) - ConvTy = CompatiblePointerDiscardsQualifiers; - - // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or - // incomplete type and the other is a pointer to a qualified or unqualified - // version of void... - if (lhptee->isVoidType()) { - if (rhptee->isObjectType() || rhptee->isIncompleteType()) - return ConvTy; - - // As an extension, we allow cast to/from void* to function pointer. - if (rhptee->isFunctionType()) - return FunctionVoidPointer; - } - - if (rhptee->isVoidType()) { - if (lhptee->isObjectType() || lhptee->isIncompleteType()) - return ConvTy; - - // As an extension, we allow cast to/from void* to function pointer. - if (lhptee->isFunctionType()) - return FunctionVoidPointer; - } - - // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or - // unqualified versions of compatible types, ... - if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) - return IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers - return ConvTy; -} - -/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently -/// has code to accommodate several GCC extensions when type checking -/// pointers. Here are some objectionable examples that GCC considers warnings: -/// -/// int a, *pint; -/// short *pshort; -/// struct foo *pfoo; -/// -/// pint = pshort; // warning: assignment from incompatible pointer type -/// a = pint; // warning: assignment makes integer from pointer without a cast -/// pint = a; // warning: assignment makes pointer from integer without a cast -/// pint = pfoo; // warning: assignment from incompatible pointer type -/// -/// As a result, the code for dealing with pointers is more complex than the -/// C99 spec dictates. -/// Note: the warning above turn into errors when -pedantic-errors is enabled. -/// -Sema::AssignConvertType -Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { - // Get canonical types. We're not formatting these types, just comparing - // them. - lhsType = lhsType.getCanonicalType(); - rhsType = rhsType.getCanonicalType(); - - if (lhsType.getUnqualifiedType() == rhsType.getUnqualifiedType()) - return Compatible; // Common case: fast path an exact match. - - if (lhsType->isReferenceType() || rhsType->isReferenceType()) { - if (Context.referenceTypesAreCompatible(lhsType, rhsType)) - return Compatible; - return Incompatible; - } - - if (lhsType->isObjCQualifiedIdType() - || rhsType->isObjCQualifiedIdType()) { - if (Context.ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType)) - return Compatible; - return Incompatible; - } - - if (lhsType->isVectorType() || rhsType->isVectorType()) { - // For OCUVector, allow vector splats; float -> - if (const OCUVectorType *LV = lhsType->getAsOCUVectorType()) { - if (LV->getElementType().getTypePtr() == rhsType.getTypePtr()) - return Compatible; - } - - // If LHS and RHS are both vectors of integer or both vectors of floating - // point types, and the total vector length is the same, allow the - // conversion. This is a bitcast; no bits are changed but the result type - // is different. - if (getLangOptions().LaxVectorConversions && - lhsType->isVectorType() && rhsType->isVectorType()) { - if ((lhsType->isIntegerType() && rhsType->isIntegerType()) || - (lhsType->isRealFloatingType() && rhsType->isRealFloatingType())) { - if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) - return Compatible; - } - } - return Incompatible; - } - - if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) - return Compatible; - - if (lhsType->isPointerType()) { - if (rhsType->isIntegerType()) - return IntToPointer; - - if (rhsType->isPointerType()) - return CheckPointerTypesForAssignment(lhsType, rhsType); - return Incompatible; - } - - if (rhsType->isPointerType()) { - // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. - if ((lhsType->isIntegerType()) && (lhsType != Context.BoolTy)) - return PointerToInt; - - if (lhsType->isPointerType()) - return CheckPointerTypesForAssignment(lhsType, rhsType); - return Incompatible; - } - - if (isa(lhsType) && isa(rhsType)) { - if (Context.tagTypesAreCompatible(lhsType, rhsType)) - return Compatible; - } - return Incompatible; -} - -Sema::AssignConvertType -Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { - // C99 6.5.16.1p1: the left operand is a pointer and the right is - // a null pointer constant. - if ((lhsType->isPointerType() || lhsType->isObjCQualifiedIdType()) - && rExpr->isNullPointerConstant(Context)) { - ImpCastExprToType(rExpr, lhsType); - return Compatible; - } - // This check seems unnatural, however it is necessary to ensure the proper - // conversion of functions/arrays. If the conversion were done for all - // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary - // expressions that surpress this implicit conversion (&, sizeof). - // - // Suppress this for references: C99 8.5.3p5. FIXME: revisit when references - // are better understood. - if (!lhsType->isReferenceType()) - DefaultFunctionArrayConversion(rExpr); - - Sema::AssignConvertType result = - CheckAssignmentConstraints(lhsType, rExpr->getType()); - - // C99 6.5.16.1p2: The value of the right operand is converted to the - // type of the assignment expression. - if (rExpr->getType() != lhsType) - ImpCastExprToType(rExpr, lhsType); - return result; -} - -Sema::AssignConvertType -Sema::CheckCompoundAssignmentConstraints(QualType lhsType, QualType rhsType) { - return CheckAssignmentConstraints(lhsType, rhsType); -} - -QualType Sema::InvalidOperands(SourceLocation loc, Expr *&lex, Expr *&rex) { - Diag(loc, diag::err_typecheck_invalid_operands, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - return QualType(); -} - -inline QualType Sema::CheckVectorOperands(SourceLocation loc, Expr *&lex, - Expr *&rex) { - QualType lhsType = lex->getType(), rhsType = rex->getType(); - - // make sure the vector types are identical. - if (lhsType == rhsType) - return lhsType; - - // if the lhs is an ocu vector and the rhs is a scalar of the same type, - // promote the rhs to the vector type. - if (const OCUVectorType *V = lhsType->getAsOCUVectorType()) { - if (V->getElementType().getCanonicalType().getTypePtr() - == rhsType.getCanonicalType().getTypePtr()) { - ImpCastExprToType(rex, lhsType); - return lhsType; - } - } - - // if the rhs is an ocu vector and the lhs is a scalar of the same type, - // promote the lhs to the vector type. - if (const OCUVectorType *V = rhsType->getAsOCUVectorType()) { - if (V->getElementType().getCanonicalType().getTypePtr() - == lhsType.getCanonicalType().getTypePtr()) { - ImpCastExprToType(lex, rhsType); - return rhsType; - } - } - - // You cannot convert between vector values of different size. - Diag(loc, diag::err_typecheck_vector_not_convertable, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - return QualType(); -} - -inline QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) -{ - QualType lhsType = lex->getType(), rhsType = rex->getType(); - - if (lhsType->isVectorType() || rhsType->isVectorType()) - return CheckVectorOperands(loc, lex, rex); - - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return compType; - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckRemainderOperands( - Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) -{ - QualType lhsType = lex->getType(), rhsType = rex->getType(); - - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return compType; - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) -{ - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) - return CheckVectorOperands(loc, lex, rex); - - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - - // handle the common case first (both operands are arithmetic). - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return compType; - - if (lex->getType()->isPointerType() && rex->getType()->isIntegerType()) - return lex->getType(); - if (lex->getType()->isIntegerType() && rex->getType()->isPointerType()) - return rex->getType(); - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) -{ - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) - return CheckVectorOperands(loc, lex, rex); - - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - - // Enforce type constraints: C99 6.5.6p3. - - // Handle the common case first (both operands are arithmetic). - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return compType; - - // Either ptr - int or ptr - ptr. - if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { - QualType lpointee = LHSPTy->getPointeeType(); - - // The LHS must be an object type, not incomplete, function, etc. - if (!lpointee->isObjectType()) { - // Handle the GNU void* extension. - if (lpointee->isVoidType()) { - Diag(loc, diag::ext_gnu_void_ptr, - lex->getSourceRange(), rex->getSourceRange()); - } else { - Diag(loc, diag::err_typecheck_sub_ptr_object, - lex->getType().getAsString(), lex->getSourceRange()); - return QualType(); - } - } - - // The result type of a pointer-int computation is the pointer type. - if (rex->getType()->isIntegerType()) - return lex->getType(); - - // Handle pointer-pointer subtractions. - if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) { - QualType rpointee = RHSPTy->getPointeeType(); - - // RHS must be an object type, unless void (GNU). - if (!rpointee->isObjectType()) { - // Handle the GNU void* extension. - if (rpointee->isVoidType()) { - if (!lpointee->isVoidType()) - Diag(loc, diag::ext_gnu_void_ptr, - lex->getSourceRange(), rex->getSourceRange()); - } else { - Diag(loc, diag::err_typecheck_sub_ptr_object, - rex->getType().getAsString(), rex->getSourceRange()); - return QualType(); - } - } - - // Pointee types must be compatible. - if (!Context.typesAreCompatible(lpointee.getUnqualifiedType(), - rpointee.getUnqualifiedType())) { - Diag(loc, diag::err_typecheck_sub_ptr_compatible, - lex->getType().getAsString(), rex->getType().getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - return QualType(); - } - - return Context.getPointerDiffType(); - } - } - - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckShiftOperands( // C99 6.5.7 - Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { - // C99 6.5.7p2: Each of the operands shall have integer type. - if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) - return InvalidOperands(loc, lex, rex); - - // Shifts don't perform usual arithmetic conversions, they just do integer - // promotions on each operand. C99 6.5.7p3 - if (!isCompAssign) - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); - - // "The type of the result is that of the promoted left operand." - return lex->getType(); -} - -inline QualType Sema::CheckCompareOperands( // C99 6.5.8 - Expr *&lex, Expr *&rex, SourceLocation loc, bool isRelational) -{ - // C99 6.5.8p3 / C99 6.5.9p4 - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - UsualArithmeticConversions(lex, rex); - else { - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); - } - QualType lType = lex->getType(); - QualType rType = rex->getType(); - - // For non-floating point types, check for self-comparisons of the form - // x == x, x != x, x < x, etc. These always evaluate to a constant, and - // often indicate logic errors in the program. - if (!lType->isFloatingType()) { - if (DeclRefExpr* DRL = dyn_cast(lex->IgnoreParens())) - if (DeclRefExpr* DRR = dyn_cast(rex->IgnoreParens())) - if (DRL->getDecl() == DRR->getDecl()) - Diag(loc, diag::warn_selfcomparison); - } - - if (isRelational) { - if (lType->isRealType() && rType->isRealType()) - return Context.IntTy; - } else { - // Check for comparisons of floating point operands using != and ==. - if (lType->isFloatingType()) { - assert (rType->isFloatingType()); - CheckFloatComparison(loc,lex,rex); - } - - if (lType->isArithmeticType() && rType->isArithmeticType()) - return Context.IntTy; - } - - bool LHSIsNull = lex->isNullPointerConstant(Context); - bool RHSIsNull = rex->isNullPointerConstant(Context); - - // All of the following pointer related warnings are GCC extensions, except - // when handling null pointer constants. One day, we can consider making them - // errors (when -pedantic-errors is enabled). - if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2 - QualType lpointee = lType->getAsPointerType()->getPointeeType(); - QualType rpointee = rType->getAsPointerType()->getPointeeType(); - - if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2 - !lpointee->isVoidType() && !lpointee->isVoidType() && - !Context.typesAreCompatible(lpointee.getUnqualifiedType(), - rpointee.getUnqualifiedType())) { - Diag(loc, diag::ext_typecheck_comparison_of_distinct_pointers, - lType.getAsString(), rType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - } - ImpCastExprToType(rex, lType); // promote the pointer to pointer - return Context.IntTy; - } - if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType()) - && Context.ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) { - ImpCastExprToType(rex, lType); - return Context.IntTy; - } - if (lType->isPointerType() && rType->isIntegerType()) { - if (!RHSIsNull) - Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, - lType.getAsString(), rType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - ImpCastExprToType(rex, lType); // promote the integer to pointer - return Context.IntTy; - } - if (lType->isIntegerType() && rType->isPointerType()) { - if (!LHSIsNull) - Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, - lType.getAsString(), rType.getAsString(), - lex->getSourceRange(), rex->getSourceRange()); - ImpCastExprToType(lex, rType); // promote the integer to pointer - return Context.IntTy; - } - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckBitwiseOperands( - Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) -{ - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) - return CheckVectorOperands(loc, lex, rex); - - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return compType; - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] - Expr *&lex, Expr *&rex, SourceLocation loc) -{ - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); - - if (lex->getType()->isScalarType() || rex->getType()->isScalarType()) - return Context.IntTy; - return InvalidOperands(loc, lex, rex); -} - -inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1 - Expr *lex, Expr *&rex, SourceLocation loc, QualType compoundType) -{ - QualType lhsType = lex->getType(); - QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType; - Expr::isModifiableLvalueResult mlval = lex->isModifiableLvalue(); - - switch (mlval) { // C99 6.5.16p2 - case Expr::MLV_Valid: - break; - case Expr::MLV_ConstQualified: - Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange()); - return QualType(); - case Expr::MLV_ArrayType: - Diag(loc, diag::err_typecheck_array_not_modifiable_lvalue, - lhsType.getAsString(), lex->getSourceRange()); - return QualType(); - case Expr::MLV_NotObjectType: - Diag(loc, diag::err_typecheck_non_object_not_modifiable_lvalue, - lhsType.getAsString(), lex->getSourceRange()); - return QualType(); - case Expr::MLV_InvalidExpression: - Diag(loc, diag::err_typecheck_expression_not_modifiable_lvalue, - lex->getSourceRange()); - return QualType(); - case Expr::MLV_IncompleteType: - case Expr::MLV_IncompleteVoidType: - Diag(loc, diag::err_typecheck_incomplete_type_not_modifiable_lvalue, - lhsType.getAsString(), lex->getSourceRange()); - return QualType(); - case Expr::MLV_DuplicateVectorComponents: - Diag(loc, diag::err_typecheck_duplicate_vector_components_not_mlvalue, - lex->getSourceRange()); - return QualType(); - } - - AssignConvertType ConvTy; - if (compoundType.isNull()) - ConvTy = CheckSingleAssignmentConstraints(lhsType, rex); - else - ConvTy = CheckCompoundAssignmentConstraints(lhsType, rhsType); - - if (DiagnoseAssignmentResult(ConvTy, loc, lhsType, rhsType, - rex, "assigning")) - return QualType(); - - // C99 6.5.16p3: The type of an assignment expression is the type of the - // left operand unless the left operand has qualified type, in which case - // it is the unqualified version of the type of the left operand. - // C99 6.5.16.1p2: In simple assignment, the value of the right operand - // is converted to the type of the assignment expression (above). - // C++ 5.17p1: the type of the assignment expression is that of its left - // oprdu. - return lhsType.getUnqualifiedType(); -} - -inline QualType Sema::CheckCommaOperands( // C99 6.5.17 - Expr *&lex, Expr *&rex, SourceLocation loc) { - UsualUnaryConversions(rex); - return rex->getType(); -} - -/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine -/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. -QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) { - QualType resType = op->getType(); - assert(!resType.isNull() && "no type for increment/decrement expression"); - - // C99 6.5.2.4p1: We allow complex as a GCC extension. - if (const PointerType *pt = resType->getAsPointerType()) { - if (!pt->getPointeeType()->isObjectType()) { // C99 6.5.2.4p2, 6.5.6p2 - Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, - resType.getAsString(), op->getSourceRange()); - return QualType(); - } - } else if (!resType->isRealType()) { - if (resType->isComplexType()) - // C99 does not support ++/-- on complex types. - Diag(OpLoc, diag::ext_integer_increment_complex, - resType.getAsString(), op->getSourceRange()); - else { - Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, - resType.getAsString(), op->getSourceRange()); - return QualType(); - } - } - // At this point, we know we have a real, complex or pointer type. - // Now make sure the operand is a modifiable lvalue. - Expr::isModifiableLvalueResult mlval = op->isModifiableLvalue(); - if (mlval != Expr::MLV_Valid) { - // FIXME: emit a more precise diagnostic... - Diag(OpLoc, diag::err_typecheck_invalid_lvalue_incr_decr, - op->getSourceRange()); - return QualType(); - } - return resType; -} - -/// getPrimaryDecl - Helper function for CheckAddressOfOperand(). -/// This routine allows us to typecheck complex/recursive expressions -/// where the declaration is needed for type checking. Here are some -/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2]. -static ValueDecl *getPrimaryDecl(Expr *e) { - switch (e->getStmtClass()) { - case Stmt::DeclRefExprClass: - return cast(e)->getDecl(); - case Stmt::MemberExprClass: - // Fields cannot be declared with a 'register' storage class. - // &X->f is always ok, even if X is declared register. - if (cast(e)->isArrow()) - return 0; - return getPrimaryDecl(cast(e)->getBase()); - case Stmt::ArraySubscriptExprClass: { - // &X[4] and &4[X] is invalid if X is invalid and X is not a pointer. - - ValueDecl *VD = getPrimaryDecl(cast(e)->getBase()); - if (!VD || VD->getType()->isPointerType()) - return 0; - else - return VD; - } - case Stmt::UnaryOperatorClass: - return getPrimaryDecl(cast(e)->getSubExpr()); - case Stmt::ParenExprClass: - return getPrimaryDecl(cast(e)->getSubExpr()); - case Stmt::ImplicitCastExprClass: - // &X[4] when X is an array, has an implicit cast from array to pointer. - return getPrimaryDecl(cast(e)->getSubExpr()); - default: - return 0; - } -} - -/// CheckAddressOfOperand - The operand of & must be either a function -/// designator or an lvalue designating an object. If it is an lvalue, the -/// object cannot be declared with storage class register or be a bit field. -/// Note: The usual conversions are *not* applied to the operand of the & -/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. -QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { - if (getLangOptions().C99) { - // Implement C99-only parts of addressof rules. - if (UnaryOperator* uOp = dyn_cast(op)) { - if (uOp->getOpcode() == UnaryOperator::Deref) - // Per C99 6.5.3.2, the address of a deref always returns a valid result - // (assuming the deref expression is valid). - return uOp->getSubExpr()->getType(); - } - // Technically, there should be a check for array subscript - // expressions here, but the result of one is always an lvalue anyway. - } - ValueDecl *dcl = getPrimaryDecl(op); - Expr::isLvalueResult lval = op->isLvalue(); - - if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1 - if (!dcl || !isa(dcl)) {// allow function designators - // FIXME: emit more specific diag... - Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof, - op->getSourceRange()); - return QualType(); - } - } else if (MemberExpr *MemExpr = dyn_cast(op)) { // C99 6.5.3.2p1 - if (MemExpr->getMemberDecl()->isBitField()) { - Diag(OpLoc, diag::err_typecheck_address_of, - std::string("bit-field"), op->getSourceRange()); - return QualType(); - } - // Check for Apple extension for accessing vector components. - } else if (isa(op) && - cast(op)->getBase()->getType()->isVectorType()) { - Diag(OpLoc, diag::err_typecheck_address_of, - std::string("vector"), op->getSourceRange()); - return QualType(); - } else if (dcl) { // C99 6.5.3.2p1 - // We have an lvalue with a decl. Make sure the decl is not declared - // with the register storage-class specifier. - if (const VarDecl *vd = dyn_cast(dcl)) { - if (vd->getStorageClass() == VarDecl::Register) { - Diag(OpLoc, diag::err_typecheck_address_of, - std::string("register variable"), op->getSourceRange()); - return QualType(); - } - } else - assert(0 && "Unknown/unexpected decl type"); - } - // If the operand has type "type", the result has type "pointer to type". - return Context.getPointerType(op->getType()); -} - -QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) { - UsualUnaryConversions(op); - QualType qType = op->getType(); - - if (const PointerType *PT = qType->getAsPointerType()) { - // Note that per both C89 and C99, this is always legal, even - // if ptype is an incomplete type or void. - // It would be possible to warn about dereferencing a - // void pointer, but it's completely well-defined, - // and such a warning is unlikely to catch any mistakes. - return PT->getPointeeType(); - } - Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer, - qType.getAsString(), op->getSourceRange()); - return QualType(); -} - -static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode( - tok::TokenKind Kind) { - BinaryOperator::Opcode Opc; - switch (Kind) { - default: assert(0 && "Unknown binop!"); - case tok::star: Opc = BinaryOperator::Mul; break; - case tok::slash: Opc = BinaryOperator::Div; break; - case tok::percent: Opc = BinaryOperator::Rem; break; - case tok::plus: Opc = BinaryOperator::Add; break; - case tok::minus: Opc = BinaryOperator::Sub; break; - case tok::lessless: Opc = BinaryOperator::Shl; break; - case tok::greatergreater: Opc = BinaryOperator::Shr; break; - case tok::lessequal: Opc = BinaryOperator::LE; break; - case tok::less: Opc = BinaryOperator::LT; break; - case tok::greaterequal: Opc = BinaryOperator::GE; break; - case tok::greater: Opc = BinaryOperator::GT; break; - case tok::exclaimequal: Opc = BinaryOperator::NE; break; - case tok::equalequal: Opc = BinaryOperator::EQ; break; - case tok::amp: Opc = BinaryOperator::And; break; - case tok::caret: Opc = BinaryOperator::Xor; break; - case tok::pipe: Opc = BinaryOperator::Or; break; - case tok::ampamp: Opc = BinaryOperator::LAnd; break; - case tok::pipepipe: Opc = BinaryOperator::LOr; break; - case tok::equal: Opc = BinaryOperator::Assign; break; - case tok::starequal: Opc = BinaryOperator::MulAssign; break; - case tok::slashequal: Opc = BinaryOperator::DivAssign; break; - case tok::percentequal: Opc = BinaryOperator::RemAssign; break; - case tok::plusequal: Opc = BinaryOperator::AddAssign; break; - case tok::minusequal: Opc = BinaryOperator::SubAssign; break; - case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break; - case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break; - case tok::ampequal: Opc = BinaryOperator::AndAssign; break; - case tok::caretequal: Opc = BinaryOperator::XorAssign; break; - case tok::pipeequal: Opc = BinaryOperator::OrAssign; break; - case tok::comma: Opc = BinaryOperator::Comma; break; - } - return Opc; -} - -static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode( - tok::TokenKind Kind) { - UnaryOperator::Opcode Opc; - switch (Kind) { - default: assert(0 && "Unknown unary op!"); - case tok::plusplus: Opc = UnaryOperator::PreInc; break; - case tok::minusminus: Opc = UnaryOperator::PreDec; break; - case tok::amp: Opc = UnaryOperator::AddrOf; break; - case tok::star: Opc = UnaryOperator::Deref; break; - case tok::plus: Opc = UnaryOperator::Plus; break; - case tok::minus: Opc = UnaryOperator::Minus; break; - case tok::tilde: Opc = UnaryOperator::Not; break; - case tok::exclaim: Opc = UnaryOperator::LNot; break; - case tok::kw_sizeof: Opc = UnaryOperator::SizeOf; break; - case tok::kw___alignof: Opc = UnaryOperator::AlignOf; break; - case tok::kw___real: Opc = UnaryOperator::Real; break; - case tok::kw___imag: Opc = UnaryOperator::Imag; break; - case tok::kw___extension__: Opc = UnaryOperator::Extension; break; - } - return Opc; -} - -// Binary Operators. 'Tok' is the token for the operator. -Action::ExprResult Sema::ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind, - ExprTy *LHS, ExprTy *RHS) { - BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind); - Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS; - - assert((lhs != 0) && "ActOnBinOp(): missing left expression"); - assert((rhs != 0) && "ActOnBinOp(): missing right expression"); - - QualType ResultTy; // Result type of the binary operator. - QualType CompTy; // Computation type for compound assignments (e.g. '+=') - - switch (Opc) { - default: - assert(0 && "Unknown binary expr!"); - case BinaryOperator::Assign: - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, QualType()); - break; - case BinaryOperator::Mul: - case BinaryOperator::Div: - ResultTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::Rem: - ResultTy = CheckRemainderOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::Add: - ResultTy = CheckAdditionOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::Sub: - ResultTy = CheckSubtractionOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::Shl: - case BinaryOperator::Shr: - ResultTy = CheckShiftOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::LE: - case BinaryOperator::LT: - case BinaryOperator::GE: - case BinaryOperator::GT: - ResultTy = CheckCompareOperands(lhs, rhs, TokLoc, true); - break; - case BinaryOperator::EQ: - case BinaryOperator::NE: - ResultTy = CheckCompareOperands(lhs, rhs, TokLoc, false); - break; - case BinaryOperator::And: - case BinaryOperator::Xor: - case BinaryOperator::Or: - ResultTy = CheckBitwiseOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::LAnd: - case BinaryOperator::LOr: - ResultTy = CheckLogicalOperands(lhs, rhs, TokLoc); - break; - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - CompTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc, true); - if (!CompTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); - break; - case BinaryOperator::RemAssign: - CompTy = CheckRemainderOperands(lhs, rhs, TokLoc, true); - if (!CompTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); - break; - case BinaryOperator::AddAssign: - CompTy = CheckAdditionOperands(lhs, rhs, TokLoc, true); - if (!CompTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); - break; - case BinaryOperator::SubAssign: - CompTy = CheckSubtractionOperands(lhs, rhs, TokLoc, true); - if (!CompTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); - break; - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - CompTy = CheckShiftOperands(lhs, rhs, TokLoc, true); - if (!CompTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); - break; - case BinaryOperator::AndAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::OrAssign: - CompTy = CheckBitwiseOperands(lhs, rhs, TokLoc, true); - if (!CompTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); - break; - case BinaryOperator::Comma: - ResultTy = CheckCommaOperands(lhs, rhs, TokLoc); - break; - } - if (ResultTy.isNull()) - return true; - if (CompTy.isNull()) - return new BinaryOperator(lhs, rhs, Opc, ResultTy, TokLoc); - else - return new CompoundAssignOperator(lhs, rhs, Opc, ResultTy, CompTy, TokLoc); -} - -// Unary Operators. 'Tok' is the token for the operator. -Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, - ExprTy *input) { - Expr *Input = (Expr*)input; - UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); - QualType resultType; - switch (Opc) { - default: - assert(0 && "Unimplemented unary expr!"); - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - resultType = CheckIncrementDecrementOperand(Input, OpLoc); - break; - case UnaryOperator::AddrOf: - resultType = CheckAddressOfOperand(Input, OpLoc); - break; - case UnaryOperator::Deref: - DefaultFunctionArrayConversion(Input); - resultType = CheckIndirectionOperand(Input, OpLoc); - break; - case UnaryOperator::Plus: - case UnaryOperator::Minus: - UsualUnaryConversions(Input); - resultType = Input->getType(); - if (!resultType->isArithmeticType()) // C99 6.5.3.3p1 - return Diag(OpLoc, diag::err_typecheck_unary_expr, - resultType.getAsString()); - break; - case UnaryOperator::Not: // bitwise complement - UsualUnaryConversions(Input); - resultType = Input->getType(); - // C99 6.5.3.3p1. We allow complex as a GCC extension. - if (!resultType->isIntegerType()) { - if (resultType->isComplexType()) - // C99 does not support '~' for complex conjugation. - Diag(OpLoc, diag::ext_integer_complement_complex, - resultType.getAsString()); - else - return Diag(OpLoc, diag::err_typecheck_unary_expr, - resultType.getAsString()); - } - break; - case UnaryOperator::LNot: // logical negation - // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). - DefaultFunctionArrayConversion(Input); - resultType = Input->getType(); - if (!resultType->isScalarType()) // C99 6.5.3.3p1 - return Diag(OpLoc, diag::err_typecheck_unary_expr, - resultType.getAsString()); - // LNot always has type int. C99 6.5.3.3p5. - resultType = Context.IntTy; - break; - case UnaryOperator::SizeOf: - resultType = CheckSizeOfAlignOfOperand(Input->getType(), OpLoc, true); - break; - case UnaryOperator::AlignOf: - resultType = CheckSizeOfAlignOfOperand(Input->getType(), OpLoc, false); - break; - case UnaryOperator::Real: - case UnaryOperator::Imag: - resultType = CheckRealImagOperand(Input, OpLoc); - break; - case UnaryOperator::Extension: - resultType = Input->getType(); - break; - } - if (resultType.isNull()) - return true; - return new UnaryOperator(Input, Opc, resultType, OpLoc); -} - -/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". -Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, - SourceLocation LabLoc, - IdentifierInfo *LabelII) { - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = LabelMap[LabelII]; - - // If we haven't seen this label yet, create a forward reference. - if (LabelDecl == 0) - LabelDecl = new LabelStmt(LabLoc, LabelII, 0); - - // Create the AST node. The address of a label always has type 'void*'. - return new AddrLabelExpr(OpLoc, LabLoc, LabelDecl, - Context.getPointerType(Context.VoidTy)); -} - -Sema::ExprResult Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtTy *substmt, - SourceLocation RPLoc) { // "({..})" - Stmt *SubStmt = static_cast(substmt); - assert(SubStmt && isa(SubStmt) && "Invalid action invocation!"); - CompoundStmt *Compound = cast(SubStmt); - - // FIXME: there are a variety of strange constraints to enforce here, for - // example, it is not possible to goto into a stmt expression apparently. - // More semantic analysis is needed. - - // FIXME: the last statement in the compount stmt has its value used. We - // should not warn about it being unused. - - // If there are sub stmts in the compound stmt, take the type of the last one - // as the type of the stmtexpr. - QualType Ty = Context.VoidTy; - - if (!Compound->body_empty()) - if (Expr *LastExpr = dyn_cast(Compound->body_back())) - Ty = LastExpr->getType(); - - return new StmtExpr(Compound, Ty, LPLoc, RPLoc); -} - -Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, - SourceLocation TypeLoc, - TypeTy *argty, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RPLoc) { - QualType ArgTy = QualType::getFromOpaquePtr(argty); - assert(!ArgTy.isNull() && "Missing type argument!"); - - // We must have at least one component that refers to the type, and the first - // one is known to be a field designator. Verify that the ArgTy represents - // a struct/union/class. - if (!ArgTy->isRecordType()) - return Diag(TypeLoc, diag::err_offsetof_record_type,ArgTy.getAsString()); - - // Otherwise, create a compound literal expression as the base, and - // iteratively process the offsetof designators. - Expr *Res = new CompoundLiteralExpr(SourceLocation(), ArgTy, 0, false); - - // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a - // GCC extension, diagnose them. - if (NumComponents != 1) - Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator, - SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd)); - - for (unsigned i = 0; i != NumComponents; ++i) { - const OffsetOfComponent &OC = CompPtr[i]; - if (OC.isBrackets) { - // Offset of an array sub-field. TODO: Should we allow vector elements? - const ArrayType *AT = Res->getType()->getAsArrayType(); - if (!AT) { - delete Res; - return Diag(OC.LocEnd, diag::err_offsetof_array_type, - Res->getType().getAsString()); - } - - // FIXME: C++: Verify that operator[] isn't overloaded. - - // C99 6.5.2.1p1 - Expr *Idx = static_cast(OC.U.E); - if (!Idx->getType()->isIntegerType()) - return Diag(Idx->getLocStart(), diag::err_typecheck_subscript, - Idx->getSourceRange()); - - Res = new ArraySubscriptExpr(Res, Idx, AT->getElementType(), OC.LocEnd); - continue; - } - - const RecordType *RC = Res->getType()->getAsRecordType(); - if (!RC) { - delete Res; - return Diag(OC.LocEnd, diag::err_offsetof_record_type, - Res->getType().getAsString()); - } - - // Get the decl corresponding to this. - RecordDecl *RD = RC->getDecl(); - FieldDecl *MemberDecl = RD->getMember(OC.U.IdentInfo); - if (!MemberDecl) - return Diag(BuiltinLoc, diag::err_typecheck_no_member, - OC.U.IdentInfo->getName(), - SourceRange(OC.LocStart, OC.LocEnd)); - - // FIXME: C++: Verify that MemberDecl isn't a static field. - // FIXME: Verify that MemberDecl isn't a bitfield. - // MemberDecl->getType() doesn't get the right qualifiers, but it doesn't - // matter here. - Res = new MemberExpr(Res, false, MemberDecl, OC.LocEnd, MemberDecl->getType()); - } - - return new UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(), - BuiltinLoc); -} - - -Sema::ExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeTy *arg1, TypeTy *arg2, - SourceLocation RPLoc) { - QualType argT1 = QualType::getFromOpaquePtr(arg1); - QualType argT2 = QualType::getFromOpaquePtr(arg2); - - assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); - - return new TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1, argT2,RPLoc); -} - -Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond, - ExprTy *expr1, ExprTy *expr2, - SourceLocation RPLoc) { - Expr *CondExpr = static_cast(cond); - Expr *LHSExpr = static_cast(expr1); - Expr *RHSExpr = static_cast(expr2); - - assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); - - // The conditional expression is required to be a constant expression. - llvm::APSInt condEval(32); - SourceLocation ExpLoc; - if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc)) - return Diag(ExpLoc, diag::err_typecheck_choose_expr_requires_constant, - CondExpr->getSourceRange()); - - // If the condition is > zero, then the AST type is the same as the LSHExpr. - QualType resType = condEval.getZExtValue() ? LHSExpr->getType() : - RHSExpr->getType(); - return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc); -} - -/// ExprsMatchFnType - return true if the Exprs in array Args have -/// QualTypes that match the QualTypes of the arguments of the FnType. -/// The number of arguments has already been validated to match the number of -/// arguments in FnType. -static bool ExprsMatchFnType(Expr **Args, const FunctionTypeProto *FnType) { - unsigned NumParams = FnType->getNumArgs(); - for (unsigned i = 0; i != NumParams; ++i) - if (Args[i]->getType().getCanonicalType() != - FnType->getArgType(i).getCanonicalType()) - return false; - return true; -} - -Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc) { - // __builtin_overload requires at least 2 arguments - if (NumArgs < 2) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, - SourceRange(BuiltinLoc, RParenLoc)); - - // The first argument is required to be a constant expression. It tells us - // the number of arguments to pass to each of the functions to be overloaded. - Expr **Args = reinterpret_cast(args); - Expr *NParamsExpr = Args[0]; - llvm::APSInt constEval(32); - SourceLocation ExpLoc; - if (!NParamsExpr->isIntegerConstantExpr(constEval, Context, &ExpLoc)) - return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant, - NParamsExpr->getSourceRange()); - - // Verify that the number of parameters is > 0 - unsigned NumParams = constEval.getZExtValue(); - if (NumParams == 0) - return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant, - NParamsExpr->getSourceRange()); - // Verify that we have at least 1 + NumParams arguments to the builtin. - if ((NumParams + 1) > NumArgs) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, - SourceRange(BuiltinLoc, RParenLoc)); - - // Figure out the return type, by matching the args to one of the functions - // listed after the parameters. - OverloadExpr *OE = 0; - for (unsigned i = NumParams + 1; i < NumArgs; ++i) { - // UsualUnaryConversions will convert the function DeclRefExpr into a - // pointer to function. - Expr *Fn = UsualUnaryConversions(Args[i]); - FunctionTypeProto *FnType = 0; - if (const PointerType *PT = Fn->getType()->getAsPointerType()) { - QualType PointeeType = PT->getPointeeType().getCanonicalType(); - FnType = dyn_cast(PointeeType); - } - - // The Expr type must be FunctionTypeProto, since FunctionTypeProto has no - // parameters, and the number of parameters must match the value passed to - // the builtin. - if (!FnType || (FnType->getNumArgs() != NumParams)) - return Diag(Fn->getExprLoc(), diag::err_overload_incorrect_fntype, - Fn->getSourceRange()); - - // Scan the parameter list for the FunctionType, checking the QualType of - // each parameter against the QualTypes of the arguments to the builtin. - // If they match, return a new OverloadExpr. - if (ExprsMatchFnType(Args+1, FnType)) { - if (OE) - return Diag(Fn->getExprLoc(), diag::err_overload_multiple_match, - OE->getFn()->getSourceRange()); - // Remember our match, and continue processing the remaining arguments - // to catch any errors. - OE = new OverloadExpr(Args, NumArgs, i, FnType->getResultType(), - BuiltinLoc, RParenLoc); - } - } - // Return the newly created OverloadExpr node, if we succeded in matching - // exactly one of the candidate functions. - if (OE) - return OE; - - // If we didn't find a matching function Expr in the __builtin_overload list - // the return an error. - std::string typeNames; - for (unsigned i = 0; i != NumParams; ++i) { - if (i != 0) typeNames += ", "; - typeNames += Args[i+1]->getType().getAsString(); - } - - return Diag(BuiltinLoc, diag::err_overload_no_match, typeNames, - SourceRange(BuiltinLoc, RParenLoc)); -} - -Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, - ExprTy *expr, TypeTy *type, - SourceLocation RPLoc) { - Expr *E = static_cast(expr); - QualType T = QualType::getFromOpaquePtr(type); - - InitBuiltinVaListType(); - - if (CheckAssignmentConstraints(Context.getBuiltinVaListType(), E->getType()) - != Compatible) - return Diag(E->getLocStart(), - diag::err_first_argument_to_va_arg_not_of_type_va_list, - E->getType().getAsString(), - E->getSourceRange()); - - // FIXME: Warn if a non-POD type is passed in. - - return new VAArgExpr(BuiltinLoc, E, T, RPLoc); -} - -bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, - SourceLocation Loc, - QualType DstType, QualType SrcType, - Expr *SrcExpr, const char *Flavor) { - // Decode the result (notice that AST's are still created for extensions). - bool isInvalid = false; - unsigned DiagKind; - switch (ConvTy) { - default: assert(0 && "Unknown conversion type"); - case Compatible: return false; - case PointerToInt: - DiagKind = diag::ext_typecheck_convert_pointer_int; - break; - case IntToPointer: - DiagKind = diag::ext_typecheck_convert_int_pointer; - break; - case IncompatiblePointer: - DiagKind = diag::ext_typecheck_convert_incompatible_pointer; - break; - case FunctionVoidPointer: - DiagKind = diag::ext_typecheck_convert_pointer_void_func; - break; - case CompatiblePointerDiscardsQualifiers: - DiagKind = diag::ext_typecheck_convert_discards_qualifiers; - break; - case Incompatible: - DiagKind = diag::err_typecheck_convert_incompatible; - isInvalid = true; - break; - } - - Diag(Loc, DiagKind, DstType.getAsString(), SrcType.getAsString(), Flavor, - SrcExpr->getSourceRange()); - return isInvalid; -} - diff --git a/clang/Sema/SemaExprCXX.cpp b/clang/Sema/SemaExprCXX.cpp deleted file mode 100644 index e49a43c4728..00000000000 --- a/clang/Sema/SemaExprCXX.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for C++ expressions. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/ASTContext.h" -using namespace clang; - -/// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. -Action::ExprResult -Sema::ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, TypeTy *Ty, - SourceLocation RAngleBracketLoc, - SourceLocation LParenLoc, ExprTy *E, - SourceLocation RParenLoc) { - CXXCastExpr::Opcode Op; - - switch (Kind) { - default: assert(0 && "Unknown C++ cast!"); - case tok::kw_const_cast: Op = CXXCastExpr::ConstCast; break; - case tok::kw_dynamic_cast: Op = CXXCastExpr::DynamicCast; break; - case tok::kw_reinterpret_cast: Op = CXXCastExpr::ReinterpretCast; break; - case tok::kw_static_cast: Op = CXXCastExpr::StaticCast; break; - } - - return new CXXCastExpr(Op, QualType::getFromOpaquePtr(Ty), (Expr*)E, OpLoc); -} - -/// ActOnCXXBoolLiteral - Parse {true,false} literals. -Action::ExprResult -Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { - assert((Kind != tok::kw_true || Kind != tok::kw_false) && - "Unknown C++ Boolean value!"); - return new CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc); -} - -/// ActOnCXXThrow - Parse throw expressions. -Action::ExprResult -Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprTy *E) { - return new CXXThrowExpr((Expr*)E, Context.VoidTy, OpLoc); -} diff --git a/clang/Sema/SemaExprObjC.cpp b/clang/Sema/SemaExprObjC.cpp deleted file mode 100644 index 4cf435c3315..00000000000 --- a/clang/Sema/SemaExprObjC.cpp +++ /dev/null @@ -1,297 +0,0 @@ -//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for Objective-C expressions. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/Expr.h" -using namespace clang; - -Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, - ExprTy **Strings, - unsigned NumStrings) { - SourceLocation AtLoc = AtLocs[0]; - StringLiteral* S = static_cast(Strings[0]); - if (NumStrings > 1) { - // Concatenate objc strings. - StringLiteral* ES = static_cast(Strings[NumStrings-1]); - SourceLocation EndLoc = ES->getSourceRange().getEnd(); - unsigned Length = 0; - for (unsigned i = 0; i < NumStrings; i++) - Length += static_cast(Strings[i])->getByteLength(); - char *strBuf = new char [Length]; - char *p = strBuf; - bool isWide = false; - for (unsigned i = 0; i < NumStrings; i++) { - S = static_cast(Strings[i]); - if (S->isWide()) - isWide = true; - memcpy(p, S->getStrData(), S->getByteLength()); - p += S->getByteLength(); - delete S; - } - S = new StringLiteral(strBuf, Length, - isWide, Context.getPointerType(Context.CharTy), - AtLoc, EndLoc); - } - - if (CheckBuiltinCFStringArgument(S)) - return true; - - if (Context.getObjCConstantStringInterface().isNull()) { - // Initialize the constant string interface lazily. This assumes - // the NSConstantString interface is seen in this translation unit. - IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString"); - ScopedDecl *IFace = LookupScopedDecl(NSIdent, Decl::IDNS_Ordinary, - SourceLocation(), TUScope); - ObjCInterfaceDecl *strIFace = dyn_cast_or_null(IFace); - if (!strIFace) - return Diag(S->getLocStart(), diag::err_undef_interface, - NSIdent->getName()); - Context.setObjCConstantStringInterface(strIFace); - } - QualType t = Context.getObjCConstantStringInterface(); - t = Context.getPointerType(t); - return new ObjCStringLiteral(S, t, AtLoc); -} - -Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, - SourceLocation EncodeLoc, - SourceLocation LParenLoc, - TypeTy *Ty, - SourceLocation RParenLoc) { - QualType EncodedType = QualType::getFromOpaquePtr(Ty); - - QualType t = Context.getPointerType(Context.CharTy); - return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); -} - -Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, - SourceLocation AtLoc, - SourceLocation SelLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - QualType t = Context.getObjCSelType(); - return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc); -} - -Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - ObjCProtocolDecl* PDecl = ObjCProtocols[ProtocolId]; - if (!PDecl) { - Diag(ProtoLoc, diag::err_undeclared_protocol, ProtocolId->getName()); - return true; - } - - QualType t = Context.getObjCProtoType(); - if (t.isNull()) - return true; - t = Context.getPointerType(t); - return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc); -} - -bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, - ObjCMethodDecl *Method) { - bool anyIncompatibleArgs = false; - - for (unsigned i = 0; i < NumArgs; i++) { - Expr *argExpr = Args[i]; - assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); - - QualType lhsType = Method->getParamDecl(i)->getType(); - QualType rhsType = argExpr->getType(); - - // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. - if (const ArrayType *ary = lhsType->getAsArrayType()) - lhsType = Context.getPointerType(ary->getElementType()); - else if (lhsType->isFunctionType()) - lhsType = Context.getPointerType(lhsType); - - AssignConvertType Result = CheckSingleAssignmentConstraints(lhsType, - argExpr); - if (Args[i] != argExpr) // The expression was converted. - Args[i] = argExpr; // Make sure we store the converted expression. - - anyIncompatibleArgs |= - DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, - argExpr, "sending"); - } - return anyIncompatibleArgs; -} - -// ActOnClassMessage - used for both unary and keyword messages. -// ArgExprs is optional - if it is present, the number of expressions -// is obtained from Sel.getNumArgs(). -Sema::ExprResult Sema::ActOnClassMessage( - Scope *S, - IdentifierInfo *receiverName, Selector Sel, - SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs) -{ - assert(receiverName && "missing receiver class name"); - - Expr **ArgExprs = reinterpret_cast(Args); - ObjCInterfaceDecl* ClassDecl = 0; - if (!strcmp(receiverName->getName(), "super") && CurMethodDecl) { - ClassDecl = CurMethodDecl->getClassInterface()->getSuperClass(); - if (ClassDecl && CurMethodDecl->isInstance()) { - // Synthesize a cast to the super class. This hack allows us to loosely - // represent super without creating a special expression node. - IdentifierInfo &II = Context.Idents.get("self"); - ExprResult ReceiverExpr = ActOnIdentifierExpr(S, lbrac, II, false); - QualType superTy = Context.getObjCInterfaceType(ClassDecl); - superTy = Context.getPointerType(superTy); - ReceiverExpr = ActOnCastExpr(SourceLocation(), superTy.getAsOpaquePtr(), - SourceLocation(), ReceiverExpr.Val); - // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac, - Args, NumArgs); - } - // We are sending a message to 'super' within a class method. Do nothing, - // the receiver will pass through as 'super' (how convenient:-). - } else - ClassDecl = getObjCInterfaceDecl(receiverName); - - // FIXME: can ClassDecl ever be null? - ObjCMethodDecl *Method = ClassDecl->lookupClassMethod(Sel); - QualType returnType; - - // Before we give up, check if the selector is an instance method. - if (!Method) - Method = ClassDecl->lookupInstanceMethod(Sel); - if (!Method) { - Diag(lbrac, diag::warn_method_not_found, std::string("+"), Sel.getName(), - SourceRange(lbrac, rbrac)); - returnType = Context.getObjCIdType(); - } else { - returnType = Method->getResultType(); - if (Sel.getNumArgs()) { - if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method)) - return true; - } - } - return new ObjCMessageExpr(receiverName, Sel, returnType, Method, - lbrac, rbrac, ArgExprs, NumArgs); -} - -// ActOnInstanceMessage - used for both unary and keyword messages. -// ArgExprs is optional - if it is present, the number of expressions -// is obtained from Sel.getNumArgs(). -Sema::ExprResult Sema::ActOnInstanceMessage( - ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs) -{ - assert(receiver && "missing receiver expression"); - - Expr **ArgExprs = reinterpret_cast(Args); - Expr *RExpr = static_cast(receiver); - QualType receiverType = RExpr->getType().getCanonicalType(); - QualType returnType; - ObjCMethodDecl *Method = 0; - - // FIXME: This code is not stripping off type qualifiers! Should it? - if (receiverType == Context.getObjCIdType().getCanonicalType() || - receiverType == Context.getObjCClassType().getCanonicalType()) { - Method = InstanceMethodPool[Sel].Method; - if (!Method) - Method = FactoryMethodPool[Sel].Method; - if (!Method) { - Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(), - SourceRange(lbrac, rbrac)); - returnType = Context.getObjCIdType(); - } else { - returnType = Method->getResultType(); - if (Sel.getNumArgs()) - if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method)) - return true; - } - } else { - bool receiverIsQualId = isa(receiverType); - // FIXME (snaroff): checking in this code from Patrick. Needs to be - // revisited. how do we get the ClassDecl from the receiver expression? - if (!receiverIsQualId) - while (const PointerType *PTy = receiverType->getAsPointerType()) - receiverType = PTy->getPointeeType(); - - ObjCInterfaceDecl* ClassDecl = 0; - if (ObjCQualifiedInterfaceType *QIT = - dyn_cast(receiverType)) { - ClassDecl = QIT->getDecl(); - Method = ClassDecl->lookupInstanceMethod(Sel); - if (!Method) { - // search protocols - for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { - ObjCProtocolDecl *PDecl = QIT->getProtocols(i); - if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) - break; - } - } - if (!Method) - Diag(lbrac, diag::warn_method_not_found_in_protocol, - std::string("-"), Sel.getName(), - SourceRange(lbrac, rbrac)); - } - else if (ObjCQualifiedIdType *QIT = - dyn_cast(receiverType)) { - // search protocols - for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { - ObjCProtocolDecl *PDecl = QIT->getProtocols(i); - if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) - break; - } - if (!Method) - Diag(lbrac, diag::warn_method_not_found_in_protocol, - std::string("-"), Sel.getName(), - SourceRange(lbrac, rbrac)); - } - else { - ObjCInterfaceType *OCIReceiver =dyn_cast(receiverType); - if (OCIReceiver == 0) { - Diag(lbrac, diag::error_bad_receiver_type, - RExpr->getType().getAsString()); - return true; - } - ClassDecl = OCIReceiver->getDecl(); - // FIXME: consider using InstanceMethodPool, since it will be faster - // than the following method (which can do *many* linear searches). The - // idea is to add class info to InstanceMethodPool... - Method = ClassDecl->lookupInstanceMethod(Sel); - } - if (!Method) { - // If we have an implementation in scope, check "private" methods. - if (ClassDecl) - if (ObjCImplementationDecl *ImpDecl = - ObjCImplementations[ClassDecl->getIdentifier()]) - Method = ImpDecl->getInstanceMethod(Sel); - // If we still haven't found a method, look in the global pool. This - // behavior isn't very desirable, however we need it for GCC - // compatibility. - if (!Method) - Method = InstanceMethodPool[Sel].Method; - } - if (!Method) { - Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(), - SourceRange(lbrac, rbrac)); - returnType = Context.getObjCIdType(); - } else { - returnType = Method->getResultType(); - if (Sel.getNumArgs()) - if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method)) - return true; - } - } - return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, - ArgExprs, NumArgs); -} diff --git a/clang/Sema/SemaStmt.cpp b/clang/Sema/SemaStmt.cpp deleted file mode 100644 index 14b2fdf7d0e..00000000000 --- a/clang/Sema/SemaStmt.cpp +++ /dev/null @@ -1,821 +0,0 @@ -//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for statements. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Stmt.h" -#include "clang/Parse/Scope.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LangOptions.h" -#include "llvm/ADT/SmallString.h" -using namespace clang; - -Sema::StmtResult Sema::ActOnExprStmt(ExprTy *expr) { - Expr *E = static_cast(expr); - assert(E && "ActOnExprStmt(): missing expression"); - return E; -} - - -Sema::StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) { - return new NullStmt(SemiLoc); -} - -Sema::StmtResult Sema::ActOnDeclStmt(DeclTy *decl, SourceLocation StartLoc, - SourceLocation EndLoc) { - if (decl == 0) - return true; - - ScopedDecl *SD = cast(static_cast(decl)); - return new DeclStmt(SD, StartLoc, EndLoc); -} - -Action::StmtResult -Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, - StmtTy **elts, unsigned NumElts, bool isStmtExpr) { - Stmt **Elts = reinterpret_cast(elts); - // If we're in C89 mode, check that we don't have any decls after stmts. If - // so, emit an extension diagnostic. - if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) { - // Note that __extension__ can be around a decl. - unsigned i = 0; - // Skip over all declarations. - for (; i != NumElts && isa(Elts[i]); ++i) - /*empty*/; - - // We found the end of the list or a statement. Scan for another declstmt. - for (; i != NumElts && !isa(Elts[i]); ++i) - /*empty*/; - - if (i != NumElts) { - ScopedDecl *D = cast(Elts[i])->getDecl(); - Diag(D->getLocation(), diag::ext_mixed_decls_code); - } - } - // Warn about unused expressions in statements. - for (unsigned i = 0; i != NumElts; ++i) { - Expr *E = dyn_cast(Elts[i]); - if (!E) continue; - - // Warn about expressions with unused results. - if (E->hasLocalSideEffect() || E->getType()->isVoidType()) - continue; - - // The last expr in a stmt expr really is used. - if (isStmtExpr && i == NumElts-1) - continue; - - /// DiagnoseDeadExpr - This expression is side-effect free and evaluated in - /// a context where the result is unused. Emit a diagnostic to warn about - /// this. - if (const BinaryOperator *BO = dyn_cast(E)) - Diag(BO->getOperatorLoc(), diag::warn_unused_expr, - BO->getLHS()->getSourceRange(), BO->getRHS()->getSourceRange()); - else if (const UnaryOperator *UO = dyn_cast(E)) - Diag(UO->getOperatorLoc(), diag::warn_unused_expr, - UO->getSubExpr()->getSourceRange()); - else - Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange()); - } - - return new CompoundStmt(Elts, NumElts, L, R); -} - -Action::StmtResult -Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval, - SourceLocation DotDotDotLoc, ExprTy *rhsval, - SourceLocation ColonLoc, StmtTy *subStmt) { - Stmt *SubStmt = static_cast(subStmt); - Expr *LHSVal = ((Expr *)lhsval), *RHSVal = ((Expr *)rhsval); - assert((LHSVal != 0) && "missing expression in case statement"); - - SourceLocation ExpLoc; - // C99 6.8.4.2p3: The expression shall be an integer constant. - if (!LHSVal->isIntegerConstantExpr(Context, &ExpLoc)) { - Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, - LHSVal->getSourceRange()); - return SubStmt; - } - - // GCC extension: The expression shall be an integer constant. - if (RHSVal && !RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) { - Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, - RHSVal->getSourceRange()); - RHSVal = 0; // Recover by just forgetting about it. - } - - if (SwitchStack.empty()) { - Diag(CaseLoc, diag::err_case_not_in_switch); - return SubStmt; - } - - CaseStmt *CS = new CaseStmt(LHSVal, RHSVal, SubStmt, CaseLoc); - SwitchStack.back()->addSwitchCase(CS); - return CS; -} - -Action::StmtResult -Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, - StmtTy *subStmt, Scope *CurScope) { - Stmt *SubStmt = static_cast(subStmt); - - if (SwitchStack.empty()) { - Diag(DefaultLoc, diag::err_default_not_in_switch); - return SubStmt; - } - - DefaultStmt *DS = new DefaultStmt(DefaultLoc, SubStmt); - SwitchStack.back()->addSwitchCase(DS); - - return DS; -} - -Action::StmtResult -Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, - SourceLocation ColonLoc, StmtTy *subStmt) { - Stmt *SubStmt = static_cast(subStmt); - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = LabelMap[II]; - - // If not forward referenced or defined already, just create a new LabelStmt. - if (LabelDecl == 0) - return LabelDecl = new LabelStmt(IdentLoc, II, SubStmt); - - assert(LabelDecl->getID() == II && "Label mismatch!"); - - // Otherwise, this label was either forward reference or multiply defined. If - // multiply defined, reject it now. - if (LabelDecl->getSubStmt()) { - Diag(IdentLoc, diag::err_redefinition_of_label, LabelDecl->getName()); - Diag(LabelDecl->getIdentLoc(), diag::err_previous_definition); - return SubStmt; - } - - // Otherwise, this label was forward declared, and we just found its real - // definition. Fill in the forward definition and return it. - LabelDecl->setIdentLoc(IdentLoc); - LabelDecl->setSubStmt(SubStmt); - return LabelDecl; -} - -Action::StmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal, - StmtTy *ThenVal, SourceLocation ElseLoc, - StmtTy *ElseVal) { - Expr *condExpr = (Expr *)CondVal; - Stmt *thenStmt = (Stmt *)ThenVal; - - assert(condExpr && "ActOnIfStmt(): missing expression"); - - DefaultFunctionArrayConversion(condExpr); - QualType condType = condExpr->getType(); - - if (!condType->isScalarType()) // C99 6.8.4.1p1 - return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar, - condType.getAsString(), condExpr->getSourceRange()); - - // Warn if the if block has a null body without an else value. - // this helps prevent bugs due to typos, such as - // if (condition); - // do_stuff(); - if (!ElseVal) { - if (NullStmt* stmt = dyn_cast(thenStmt)) - Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); - } - - return new IfStmt(IfLoc, condExpr, thenStmt, (Stmt*)ElseVal); -} - -Action::StmtResult -Sema::ActOnStartOfSwitchStmt(ExprTy *cond) { - Expr *Cond = static_cast(cond); - - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - UsualUnaryConversions(Cond); - - SwitchStmt *SS = new SwitchStmt(Cond); - SwitchStack.push_back(SS); - return SS; -} - -/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have -/// the specified width and sign. If an overflow occurs, detect it and emit -/// the specified diagnostic. -void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, - unsigned NewWidth, bool NewSign, - SourceLocation Loc, - unsigned DiagID) { - // Perform a conversion to the promoted condition type if needed. - if (NewWidth > Val.getBitWidth()) { - // If this is an extension, just do it. - llvm::APSInt OldVal(Val); - Val.extend(NewWidth); - - // If the input was signed and negative and the output is unsigned, - // warn. - if (!NewSign && OldVal.isSigned() && OldVal.isNegative()) - Diag(Loc, DiagID, OldVal.toString(), Val.toString()); - - Val.setIsSigned(NewSign); - } else if (NewWidth < Val.getBitWidth()) { - // If this is a truncation, check for overflow. - llvm::APSInt ConvVal(Val); - ConvVal.trunc(NewWidth); - ConvVal.setIsSigned(NewSign); - ConvVal.extend(Val.getBitWidth()); - ConvVal.setIsSigned(Val.isSigned()); - if (ConvVal != Val) - Diag(Loc, DiagID, Val.toString(), ConvVal.toString()); - - // Regardless of whether a diagnostic was emitted, really do the - // truncation. - Val.trunc(NewWidth); - Val.setIsSigned(NewSign); - } else if (NewSign != Val.isSigned()) { - // Convert the sign to match the sign of the condition. This can cause - // overflow as well: unsigned(INTMIN) - llvm::APSInt OldVal(Val); - Val.setIsSigned(NewSign); - - if (Val.isNegative()) // Sign bit changes meaning. - Diag(Loc, DiagID, OldVal.toString(), Val.toString()); - } -} - -namespace { - struct CaseCompareFunctor { - bool operator()(const std::pair &LHS, - const llvm::APSInt &RHS) { - return LHS.first < RHS; - } - bool operator()(const std::pair &LHS, - const std::pair &RHS) { - return LHS.first < RHS.first; - } - bool operator()(const llvm::APSInt &LHS, - const std::pair &RHS) { - return LHS < RHS.first; - } - }; -} - -/// CmpCaseVals - Comparison predicate for sorting case values. -/// -static bool CmpCaseVals(const std::pair& lhs, - const std::pair& rhs) { - if (lhs.first < rhs.first) - return true; - - if (lhs.first == rhs.first && - lhs.second->getCaseLoc().getRawEncoding() - < rhs.second->getCaseLoc().getRawEncoding()) - return true; - return false; -} - -Action::StmtResult -Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, - ExprTy *Body) { - Stmt *BodyStmt = (Stmt*)Body; - - SwitchStmt *SS = SwitchStack.back(); - assert(SS == (SwitchStmt*)Switch && "switch stack missing push/pop!"); - - SS->setBody(BodyStmt, SwitchLoc); - SwitchStack.pop_back(); - - Expr *CondExpr = SS->getCond(); - QualType CondType = CondExpr->getType(); - - if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 - Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer, - CondType.getAsString(), CondExpr->getSourceRange()); - return true; - } - - // Get the bitwidth of the switched-on value before promotions. We must - // convert the integer case values to this width before comparison. - unsigned CondWidth = static_cast(Context.getTypeSize(CondType)); - bool CondIsSigned = CondType->isSignedIntegerType(); - - // Accumulate all of the case values in a vector so that we can sort them - // and detect duplicates. This vector contains the APInt for the case after - // it has been converted to the condition type. - typedef llvm::SmallVector, 64> CaseValsTy; - CaseValsTy CaseVals; - - // Keep track of any GNU case ranges we see. The APSInt is the low value. - std::vector > CaseRanges; - - DefaultStmt *TheDefaultStmt = 0; - - bool CaseListIsErroneous = false; - - for (SwitchCase *SC = SS->getSwitchCaseList(); SC; - SC = SC->getNextSwitchCase()) { - - if (DefaultStmt *DS = dyn_cast(SC)) { - if (TheDefaultStmt) { - Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined); - Diag(TheDefaultStmt->getDefaultLoc(), diag::err_first_label); - - // FIXME: Remove the default statement from the switch block so that - // we'll return a valid AST. This requires recursing down the - // AST and finding it, not something we are set up to do right now. For - // now, just lop the entire switch stmt out of the AST. - CaseListIsErroneous = true; - } - TheDefaultStmt = DS; - - } else { - CaseStmt *CS = cast(SC); - - // We already verified that the expression has a i-c-e value (C99 - // 6.8.4.2p3) - get that value now. - llvm::APSInt LoVal(32); - Expr *Lo = CS->getLHS(); - Lo->isIntegerConstantExpr(LoVal, Context); - - // Convert the value to the same width/sign as the condition. - ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, - CS->getLHS()->getLocStart(), - diag::warn_case_value_overflow); - - // If the LHS is not the same type as the condition, insert an implicit - // cast. - ImpCastExprToType(Lo, CondType); - CS->setLHS(Lo); - - // If this is a case range, remember it in CaseRanges, otherwise CaseVals. - if (CS->getRHS()) - CaseRanges.push_back(std::make_pair(LoVal, CS)); - else - CaseVals.push_back(std::make_pair(LoVal, CS)); - } - } - - // Sort all the scalar case values so we can easily detect duplicates. - std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); - - if (!CaseVals.empty()) { - for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { - if (CaseVals[i].first == CaseVals[i+1].first) { - // If we have a duplicate, report it. - Diag(CaseVals[i+1].second->getLHS()->getLocStart(), - diag::err_duplicate_case, CaseVals[i].first.toString()); - Diag(CaseVals[i].second->getLHS()->getLocStart(), - diag::err_duplicate_case_prev); - // FIXME: We really want to remove the bogus case stmt from the substmt, - // but we have no way to do this right now. - CaseListIsErroneous = true; - } - } - } - - // Detect duplicate case ranges, which usually don't exist at all in the first - // place. - if (!CaseRanges.empty()) { - // Sort all the case ranges by their low value so we can easily detect - // overlaps between ranges. - std::stable_sort(CaseRanges.begin(), CaseRanges.end()); - - // Scan the ranges, computing the high values and removing empty ranges. - std::vector HiVals; - for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { - CaseStmt *CR = CaseRanges[i].second; - llvm::APSInt HiVal(32); - Expr *Hi = CR->getRHS(); - Hi->isIntegerConstantExpr(HiVal, Context); - - // Convert the value to the same width/sign as the condition. - ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, - CR->getRHS()->getLocStart(), - diag::warn_case_value_overflow); - - // If the LHS is not the same type as the condition, insert an implicit - // cast. - ImpCastExprToType(Hi, CondType); - CR->setRHS(Hi); - - // If the low value is bigger than the high value, the case is empty. - if (CaseRanges[i].first > HiVal) { - Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range, - SourceRange(CR->getLHS()->getLocStart(), - CR->getRHS()->getLocEnd())); - CaseRanges.erase(CaseRanges.begin()+i); - --i, --e; - continue; - } - HiVals.push_back(HiVal); - } - - // Rescan the ranges, looking for overlap with singleton values and other - // ranges. Since the range list is sorted, we only need to compare case - // ranges with their neighbors. - for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { - llvm::APSInt &CRLo = CaseRanges[i].first; - llvm::APSInt &CRHi = HiVals[i]; - CaseStmt *CR = CaseRanges[i].second; - - // Check to see whether the case range overlaps with any singleton cases. - CaseStmt *OverlapStmt = 0; - llvm::APSInt OverlapVal(32); - - // Find the smallest value >= the lower bound. If I is in the case range, - // then we have overlap. - CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(), - CaseVals.end(), CRLo, - CaseCompareFunctor()); - if (I != CaseVals.end() && I->first < CRHi) { - OverlapVal = I->first; // Found overlap with scalar. - OverlapStmt = I->second; - } - - // Find the smallest value bigger than the upper bound. - I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor()); - if (I != CaseVals.begin() && (I-1)->first >= CRLo) { - OverlapVal = (I-1)->first; // Found overlap with scalar. - OverlapStmt = (I-1)->second; - } - - // Check to see if this case stmt overlaps with the subsequent case range. - if (i && CRLo <= HiVals[i-1]) { - OverlapVal = HiVals[i-1]; // Found overlap with range. - OverlapStmt = CaseRanges[i-1].second; - } - - if (OverlapStmt) { - // If we have a duplicate, report it. - Diag(CR->getLHS()->getLocStart(), - diag::err_duplicate_case, OverlapVal.toString()); - Diag(OverlapStmt->getLHS()->getLocStart(), - diag::err_duplicate_case_prev); - // FIXME: We really want to remove the bogus case stmt from the substmt, - // but we have no way to do this right now. - CaseListIsErroneous = true; - } - } - } - - // FIXME: If the case list was broken is some way, we don't have a good system - // to patch it up. Instead, just return the whole substmt as broken. - if (CaseListIsErroneous) - return true; - - return SS; -} - -Action::StmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) { - Expr *condExpr = (Expr *)Cond; - assert(condExpr && "ActOnWhileStmt(): missing expression"); - - DefaultFunctionArrayConversion(condExpr); - QualType condType = condExpr->getType(); - - if (!condType->isScalarType()) // C99 6.8.5p2 - return Diag(WhileLoc, diag::err_typecheck_statement_requires_scalar, - condType.getAsString(), condExpr->getSourceRange()); - - return new WhileStmt(condExpr, (Stmt*)Body, WhileLoc); -} - -Action::StmtResult -Sema::ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body, - SourceLocation WhileLoc, ExprTy *Cond) { - Expr *condExpr = (Expr *)Cond; - assert(condExpr && "ActOnDoStmt(): missing expression"); - - DefaultFunctionArrayConversion(condExpr); - QualType condType = condExpr->getType(); - - if (!condType->isScalarType()) // C99 6.8.5p2 - return Diag(DoLoc, diag::err_typecheck_statement_requires_scalar, - condType.getAsString(), condExpr->getSourceRange()); - - return new DoStmt((Stmt*)Body, condExpr, DoLoc); -} - -Action::StmtResult -Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtTy *first, ExprTy *second, ExprTy *third, - SourceLocation RParenLoc, StmtTy *body) { - Stmt *First = static_cast(first); - Expr *Second = static_cast(second); - Expr *Third = static_cast(third); - Stmt *Body = static_cast(body); - - if (DeclStmt *DS = dyn_cast_or_null(First)) { - // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare - // identifiers for objects having storage class 'auto' or 'register'. - for (ScopedDecl *D = DS->getDecl(); D; D = D->getNextDeclarator()) { - BlockVarDecl *BVD = dyn_cast(D); - if (BVD && !BVD->hasLocalStorage()) - BVD = 0; - if (BVD == 0) - Diag(dyn_cast(D)->getLocation(), - diag::err_non_variable_decl_in_for); - // FIXME: mark decl erroneous! - } - } - if (Second) { - DefaultFunctionArrayConversion(Second); - QualType SecondType = Second->getType(); - - if (!SecondType->isScalarType()) // C99 6.8.5p2 - return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar, - SecondType.getAsString(), Second->getSourceRange()); - } - return new ForStmt(First, Second, Third, Body, ForLoc); -} - -Action::StmtResult -Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, - StmtTy *first, ExprTy *second, - SourceLocation RParenLoc, StmtTy *body) { - Stmt *First = static_cast(first); - Expr *Second = static_cast(second); - Stmt *Body = static_cast(body); - if (First) { - QualType FirstType; - if (DeclStmt *DS = dyn_cast(First)) { - FirstType = cast(DS->getDecl())->getType(); - // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare - // identifiers for objects having storage class 'auto' or 'register'. - ScopedDecl *D = DS->getDecl(); - BlockVarDecl *BVD = cast(D); - if (!BVD->hasLocalStorage()) - return Diag(BVD->getLocation(), diag::err_non_variable_decl_in_for); - if (D->getNextDeclarator()) - return Diag(D->getLocation(), diag::err_toomany_element_decls); - } - else - FirstType = static_cast(first)->getType(); - if (!isObjCObjectPointerType(FirstType)) - Diag(ForLoc, diag::err_selector_element_type, - FirstType.getAsString(), First->getSourceRange()); - } - if (Second) { - DefaultFunctionArrayConversion(Second); - QualType SecondType = Second->getType(); - if (!isObjCObjectPointerType(SecondType)) - Diag(ForLoc, diag::err_collection_expr_type, - SecondType.getAsString(), Second->getSourceRange()); - } - return new ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc); -} - -Action::StmtResult -Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, - IdentifierInfo *LabelII) { - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = LabelMap[LabelII]; - - // If we haven't seen this label yet, create a forward reference. - if (LabelDecl == 0) - LabelDecl = new LabelStmt(LabelLoc, LabelII, 0); - - return new GotoStmt(LabelDecl, GotoLoc, LabelLoc); -} - -Action::StmtResult -Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc,SourceLocation StarLoc, - ExprTy *DestExp) { - // FIXME: Verify that the operand is convertible to void*. - - return new IndirectGotoStmt((Expr*)DestExp); -} - -Action::StmtResult -Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { - Scope *S = CurScope->getContinueParent(); - if (!S) { - // C99 6.8.6.2p1: A break shall appear only in or as a loop body. - Diag(ContinueLoc, diag::err_continue_not_in_loop); - return true; - } - - return new ContinueStmt(ContinueLoc); -} - -Action::StmtResult -Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { - Scope *S = CurScope->getBreakParent(); - if (!S) { - // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body. - Diag(BreakLoc, diag::err_break_not_in_loop_or_switch); - return true; - } - - return new BreakStmt(BreakLoc); -} - - -Action::StmtResult -Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) { - Expr *RetValExp = static_cast(rex); - QualType FnRetType = CurFunctionDecl ? CurFunctionDecl->getResultType() : - CurMethodDecl->getResultType(); - - if (FnRetType->isVoidType()) { - if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns) - Diag(ReturnLoc, diag::ext_return_has_expr, - (CurFunctionDecl ? CurFunctionDecl->getIdentifier()->getName() : - CurMethodDecl->getSelector().getName()), - RetValExp->getSourceRange()); - return new ReturnStmt(ReturnLoc, RetValExp); - } else { - if (!RetValExp) { - const char *funcName = CurFunctionDecl ? - CurFunctionDecl->getIdentifier()->getName() : - CurMethodDecl->getSelector().getName().c_str(); - if (getLangOptions().C99) // C99 6.8.6.4p1 (ext_ since GCC warns) - Diag(ReturnLoc, diag::ext_return_missing_expr, funcName); - else // C90 6.6.6.4p4 - Diag(ReturnLoc, diag::warn_return_missing_expr, funcName); - return new ReturnStmt(ReturnLoc, (Expr*)0); - } - } - // we have a non-void function with an expression, continue checking - QualType RetValType = RetValExp->getType(); - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - AssignConvertType ConvTy = CheckSingleAssignmentConstraints(FnRetType, - RetValExp); - if (DiagnoseAssignmentResult(ConvTy, ReturnLoc, FnRetType, - RetValType, RetValExp, "returning")) - return true; - - if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); - - return new ReturnStmt(ReturnLoc, (Expr*)RetValExp); -} - -Sema::StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, - bool IsSimple, - bool IsVolatile, - unsigned NumOutputs, - unsigned NumInputs, - std::string *Names, - ExprTy **Constraints, - ExprTy **Exprs, - ExprTy *AsmString, - unsigned NumClobbers, - ExprTy **Clobbers, - SourceLocation RParenLoc) { - Expr *E = (Expr *)AsmString; - - for (unsigned i = 0; i < NumOutputs; i++) { - StringLiteral *Literal = cast((Expr *)Constraints[i]); - assert(!Literal->isWide() && - "Output constraint strings should not be wide!"); - - std::string OutputConstraint(Literal->getStrData(), - Literal->getByteLength()); - - TargetInfo::ConstraintInfo info; - if (!Context.Target.validateOutputConstraint(OutputConstraint.c_str(), - info)) { - // FIXME: We currently leak memory here. - Diag(Literal->getLocStart(), - diag::err_invalid_output_constraint_in_asm); - return true; - } - - // Check that the output exprs are valid lvalues. - Expr *OutputExpr = (Expr *)Exprs[i]; - Expr::isLvalueResult Result = OutputExpr->isLvalue(); - if (Result != Expr::LV_Valid) { - ParenExpr *PE = cast(OutputExpr); - - Diag(PE->getSubExpr()->getLocStart(), - diag::err_invalid_lvalue_in_asm_output, - PE->getSubExpr()->getSourceRange()); - - // FIXME: We currently leak memory here. - return true; - } - } - - for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { - StringLiteral *Literal = cast((Expr *)Constraints[i]); - assert(!Literal->isWide() && - "Output constraint strings should not be wide!"); - - std::string InputConstraint(Literal->getStrData(), - Literal->getByteLength()); - - TargetInfo::ConstraintInfo info; - if (!Context.Target.validateInputConstraint(InputConstraint.c_str(), - NumOutputs, - info)) { - // FIXME: We currently leak memory here. - Diag(Literal->getLocStart(), - diag::err_invalid_input_constraint_in_asm); - return true; - } - - // Check that the input exprs aren't of type void. - Expr *InputExpr = (Expr *)Exprs[i]; - if (InputExpr->getType()->isVoidType()) { - ParenExpr *PE = cast(InputExpr); - - Diag(PE->getSubExpr()->getLocStart(), - diag::err_invalid_type_in_asm_input, - PE->getType().getAsString(), - PE->getSubExpr()->getSourceRange()); - - // FIXME: We currently leak memory here. - return true; - } - } - - // Check that the clobbers are valid. - for (unsigned i = 0; i < NumClobbers; i++) { - StringLiteral *Literal = cast((Expr *)Clobbers[i]); - assert(!Literal->isWide() && "Clobber strings should not be wide!"); - - llvm::SmallString<16> Clobber(Literal->getStrData(), - Literal->getStrData() + - Literal->getByteLength()); - - if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) { - Diag(Literal->getLocStart(), - diag::err_unknown_register_name_in_asm, - Clobber.c_str()); - - // FIXME: We currently leak memory here. - return true; - } - } - - return new AsmStmt(AsmLoc, - IsSimple, - IsVolatile, - NumOutputs, - NumInputs, - Names, - reinterpret_cast(Constraints), - reinterpret_cast(Exprs), - cast(E), - NumClobbers, - reinterpret_cast(Clobbers), - RParenLoc); -} - -Action::StmtResult -Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, - SourceLocation RParen, StmtTy *Parm, - StmtTy *Body, StmtTy *CatchList) { - ObjCAtCatchStmt *CS = new ObjCAtCatchStmt(AtLoc, RParen, - static_cast(Parm), static_cast(Body), - static_cast(CatchList)); - return CatchList ? CatchList : CS; -} - -Action::StmtResult -Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtTy *Body) { - ObjCAtFinallyStmt *FS = new ObjCAtFinallyStmt(AtLoc, - static_cast(Body)); - return FS; -} - -Action::StmtResult -Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtTy *Try, StmtTy *Catch, StmtTy *Finally) { - ObjCAtTryStmt *TS = new ObjCAtTryStmt(AtLoc, static_cast(Try), - static_cast(Catch), - static_cast(Finally)); - return TS; -} - -Action::StmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, StmtTy *Throw) { - ObjCAtThrowStmt *TS = new ObjCAtThrowStmt(AtLoc, static_cast(Throw)); - return TS; -} - -Action::StmtResult -Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprTy *SynchExpr, - StmtTy *SynchBody) { - ObjCAtSynchronizedStmt *SS = new ObjCAtSynchronizedStmt(AtLoc, - static_cast(SynchExpr), static_cast(SynchBody)); - return SS; -} - - diff --git a/clang/Sema/SemaType.cpp b/clang/Sema/SemaType.cpp deleted file mode 100644 index f717b4139a5..00000000000 --- a/clang/Sema/SemaType.cpp +++ /dev/null @@ -1,498 +0,0 @@ -//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements type-related semantic analysis. -// -//===----------------------------------------------------------------------===// - -#include "Sema.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Basic/LangOptions.h" -using namespace clang; - -/// ConvertDeclSpecToType - Convert the specified declspec to the appropriate -/// type object. This returns null on error. -QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) { - // FIXME: Should move the logic from DeclSpec::Finish to here for validity - // checking. - QualType Result; - - switch (DS.getTypeSpecType()) { - default: return QualType(); // FIXME: Handle unimp cases! - case DeclSpec::TST_void: return Context.VoidTy; - case DeclSpec::TST_char: - if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) - Result = Context.CharTy; - else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) - Result = Context.SignedCharTy; - else { - assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && - "Unknown TSS value"); - Result = Context.UnsignedCharTy; - } - break; - case DeclSpec::TST_unspecified: // Unspecific typespec defaults to int. - case DeclSpec::TST_int: { - if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { - switch (DS.getTypeSpecWidth()) { - case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; - case DeclSpec::TSW_short: Result = Context.ShortTy; break; - case DeclSpec::TSW_long: Result = Context.LongTy; break; - case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; - } - } else { - switch (DS.getTypeSpecWidth()) { - case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; - case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; - case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; - case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; - } - } - break; - } - case DeclSpec::TST_float: Result = Context.FloatTy; break; - case DeclSpec::TST_double: - if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) - Result = Context.LongDoubleTy; - else - Result = Context.DoubleTy; - break; - case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool - case DeclSpec::TST_decimal32: // _Decimal32 - case DeclSpec::TST_decimal64: // _Decimal64 - case DeclSpec::TST_decimal128: // _Decimal128 - assert(0 && "FIXME: GNU decimal extensions not supported yet!"); - case DeclSpec::TST_enum: - case DeclSpec::TST_union: - case DeclSpec::TST_struct: { - Decl *D = static_cast(DS.getTypeRep()); - assert(D && "Didn't get a decl for a enum/union/struct?"); - assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && - DS.getTypeSpecSign() == 0 && - "Can't handle qualifiers on typedef names yet!"); - // TypeQuals handled by caller. - Result = Context.getTagDeclType(cast(D)); - break; - } - case DeclSpec::TST_typedef: { - Decl *D = static_cast(DS.getTypeRep()); - assert(D && "Didn't get a decl for a typedef?"); - assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && - DS.getTypeSpecSign() == 0 && - "Can't handle qualifiers on typedef names yet!"); - // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so - // we have this "hack" for now... - if (ObjCInterfaceDecl *ObjCIntDecl = dyn_cast(D)) { - if (DS.getProtocolQualifiers() == 0) { - Result = Context.getObjCInterfaceType(ObjCIntDecl); - break; - } - - Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0]; - Result = Context.getObjCQualifiedInterfaceType(ObjCIntDecl, - reinterpret_cast(PPDecl), - DS.getNumProtocolQualifiers()); - break; - } - else if (TypedefDecl *typeDecl = dyn_cast(D)) { - if (Context.getObjCIdType() == Context.getTypedefType(typeDecl) - && DS.getProtocolQualifiers()) { - // id - Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0]; - Result = Context.getObjCQualifiedIdType(typeDecl->getUnderlyingType(), - reinterpret_cast(PPDecl), - DS.getNumProtocolQualifiers()); - break; - } - } - // TypeQuals handled by caller. - Result = Context.getTypedefType(cast(D)); - break; - } - case DeclSpec::TST_typeofType: - Result = QualType::getFromOpaquePtr(DS.getTypeRep()); - assert(!Result.isNull() && "Didn't get a type for typeof?"); - // TypeQuals handled by caller. - Result = Context.getTypeOfType(Result); - break; - case DeclSpec::TST_typeofExpr: { - Expr *E = static_cast(DS.getTypeRep()); - assert(E && "Didn't get an expression for typeof?"); - // TypeQuals handled by caller. - Result = Context.getTypeOfExpr(E); - break; - } - } - - // Handle complex types. - if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) - Result = Context.getComplexType(Result); - - assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && - "FIXME: imaginary types not supported yet!"); - - // See if there are any attributes on the declspec that apply to the type (as - // opposed to the decl). - if (AttributeList *AL = DS.getAttributes()) - DS.SetAttributes(ProcessTypeAttributes(Result, AL)); - - return Result; -} - -/// GetTypeForDeclarator - Convert the type for the specified declarator to Type -/// instances. -QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { - // long long is a C99 feature. - if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && - D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) - Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); - - QualType T = ConvertDeclSpecToType(D.getDeclSpec()); - - // Apply const/volatile/restrict qualifiers to T. - T = T.getQualifiedType(D.getDeclSpec().getTypeQualifiers()); - - // Walk the DeclTypeInfo, building the recursive type as we go. DeclTypeInfos - // are ordered from the identifier out, which is opposite of what we want :). - for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { - DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); - switch (DeclType.Kind) { - default: assert(0 && "Unknown decltype!"); - case DeclaratorChunk::Pointer: - if (T->isReferenceType()) { - // C++ 8.3.2p4: There shall be no ... pointers to references ... - Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference, - D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); - D.setInvalidType(true); - T = Context.IntTy; - } - - // Apply the pointer typequals to the pointer object. - T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals); - - // See if there are any attributes on the pointer that apply to it. - if (AttributeList *AL = DeclType.Ptr.AttrList) - DeclType.Ptr.AttrList = ProcessTypeAttributes(T, AL); - - break; - case DeclaratorChunk::Reference: - if (const ReferenceType *RT = T->getAsReferenceType()) { - // C++ 8.3.2p4: There shall be no references to references. - Diag(D.getIdentifierLoc(), - diag::err_illegal_decl_reference_to_reference, - D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); - D.setInvalidType(true); - T = RT->getReferenceeType(); - } - - T = Context.getReferenceType(T); - - // FIXME: Handle Ref.Restrict! - - // See if there are any attributes on the pointer that apply to it. - if (AttributeList *AL = DeclType.Ref.AttrList) - DeclType.Ref.AttrList = ProcessTypeAttributes(T, AL); - break; - case DeclaratorChunk::Array: { - const DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; - Expr *ArraySize = static_cast(ATI.NumElts); - ArrayType::ArraySizeModifier ASM; - if (ATI.isStar) - ASM = ArrayType::Star; - else if (ATI.hasStatic) - ASM = ArrayType::Static; - else - ASM = ArrayType::Normal; - - // C99 6.7.5.2p1: If the element type is an incomplete or function type, - // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (T->isIncompleteType()) { - Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_incomplete_type, - T.getAsString()); - T = Context.IntTy; - D.setInvalidType(true); - } else if (T->isFunctionType()) { - Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions, - D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); - T = Context.getPointerType(T); - D.setInvalidType(true); - } else if (const ReferenceType *RT = T->getAsReferenceType()) { - // C++ 8.3.2p4: There shall be no ... arrays of references ... - Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references, - D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); - T = RT->getReferenceeType(); - D.setInvalidType(true); - } else if (const RecordType *EltTy = T->getAsRecordType()) { - // If the element type is a struct or union that contains a variadic - // array, reject it: C99 6.7.2.1p2. - if (EltTy->getDecl()->hasFlexibleArrayMember()) { - Diag(DeclType.Loc, diag::err_flexible_array_in_array, - T.getAsString()); - T = Context.IntTy; - D.setInvalidType(true); - } - } - // C99 6.7.5.2p1: The size expression shall have integer type. - if (ArraySize && !ArraySize->getType()->isIntegerType()) { - Diag(ArraySize->getLocStart(), diag::err_array_size_non_int, - ArraySize->getType().getAsString(), ArraySize->getSourceRange()); - D.setInvalidType(true); - } - llvm::APSInt ConstVal(32); - // If no expression was provided, we consider it a VLA. - if (!ArraySize) { - T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals); - } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context)) { - T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals); - } else { - // C99 6.7.5.2p1: If the expression is a constant expression, it shall - // have a value greater than zero. - if (ConstVal.isSigned()) { - if (ConstVal.isNegative()) { - Diag(ArraySize->getLocStart(), - diag::err_typecheck_negative_array_size, - ArraySize->getSourceRange()); - D.setInvalidType(true); - } else if (ConstVal == 0) { - // GCC accepts zero sized static arrays. - Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size, - ArraySize->getSourceRange()); - } - } - T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals); - } - // If this is not C99, extwarn about VLA's and C99 array size modifiers. - if (!getLangOptions().C99 && - (ASM != ArrayType::Normal || - (ArraySize && !ArraySize->isIntegerConstantExpr(Context)))) - Diag(D.getIdentifierLoc(), diag::ext_vla); - break; - } - case DeclaratorChunk::Function: - // If the function declarator has a prototype (i.e. it is not () and - // does not have a K&R-style identifier list), then the arguments are part - // of the type, otherwise the argument list is (). - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - - // C99 6.7.5.3p1: The return type may not be a function or array type. - if (T->isArrayType() || T->isFunctionType()) { - Diag(DeclType.Loc, diag::err_func_returning_array_function, - T.getAsString()); - T = Context.IntTy; - D.setInvalidType(true); - } - - if (!FTI.hasPrototype) { - // Simple void foo(), where the incoming T is the result type. - T = Context.getFunctionTypeNoProto(T); - - // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. - if (FTI.NumArgs != 0) - Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); - - } else { - // Otherwise, we have a function with an argument list that is - // potentially variadic. - llvm::SmallVector ArgTys; - - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - QualType ArgTy = QualType::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo); - assert(!ArgTy.isNull() && "Couldn't parse type?"); - // - // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). - // This matches the conversion that is done in - // Sema::ActOnParamDeclarator(). Without this conversion, the - // argument type in the function prototype *will not* match the - // type in ParmVarDecl (which makes the code generator unhappy). - // - // FIXME: We still apparently need the conversion in - // Sema::ParseParamDeclarator(). This doesn't make any sense, since - // it should be driving off the type being created here. - // - // FIXME: If a source translation tool needs to see the original type, - // then we need to consider storing both types somewhere... - // - if (const ArrayType *AT = ArgTy->getAsArrayType()) { - // int x[restrict 4] -> int *restrict - ArgTy = Context.getPointerType(AT->getElementType()); - ArgTy = ArgTy.getQualifiedType(AT->getIndexTypeQualifier()); - } else if (ArgTy->isFunctionType()) - ArgTy = Context.getPointerType(ArgTy); - // Look for 'void'. void is allowed only as a single argument to a - // function with no other parameters (C99 6.7.5.3p10). We record - // int(void) as a FunctionTypeProto with an empty argument list. - else if (ArgTy->isVoidType()) { - // If this is something like 'float(int, void)', reject it. 'void' - // is an incomplete type (C99 6.2.5p19) and function decls cannot - // have arguments of incomplete type. - if (FTI.NumArgs != 1 || FTI.isVariadic) { - Diag(DeclType.Loc, diag::err_void_only_param); - ArgTy = Context.IntTy; - FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr(); - } else if (FTI.ArgInfo[i].Ident) { - // Reject, but continue to parse 'int(void abc)'. - Diag(FTI.ArgInfo[i].IdentLoc, - diag::err_param_with_void_type); - ArgTy = Context.IntTy; - FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr(); - } else { - // Reject, but continue to parse 'float(const void)'. - if (ArgTy.getCVRQualifiers()) - Diag(DeclType.Loc, diag::err_void_param_qualified); - - // Do not add 'void' to the ArgTys list. - break; - } - } - - ArgTys.push_back(ArgTy); - } - T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), - FTI.isVariadic); - } - break; - } - } - - return T; -} - -/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition -/// declarator -QualType Sema::ObjCGetTypeForMethodDefinition(DeclTy *D) { - ObjCMethodDecl *MDecl = dyn_cast(static_cast(D)); - QualType T = MDecl->getResultType(); - llvm::SmallVector ArgTys; - - // Add the first two invisible argument types for self and _cmd. - if (MDecl->isInstance()) { - QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface()); - selfTy = Context.getPointerType(selfTy); - ArgTys.push_back(selfTy); - } - else - ArgTys.push_back(Context.getObjCIdType()); - ArgTys.push_back(Context.getObjCSelType()); - - for (int i = 0; i < MDecl->getNumParams(); i++) { - ParmVarDecl *PDecl = MDecl->getParamDecl(i); - QualType ArgTy = PDecl->getType(); - assert(!ArgTy.isNull() && "Couldn't parse type?"); - // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). - // This matches the conversion that is done in - // Sema::ParseParamDeclarator(). - if (const ArrayType *AT = ArgTy->getAsArrayType()) - ArgTy = Context.getPointerType(AT->getElementType()); - else if (ArgTy->isFunctionType()) - ArgTy = Context.getPointerType(ArgTy); - ArgTys.push_back(ArgTy); - } - T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), - MDecl->isVariadic()); - return T; -} - -Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { - // C99 6.7.6: Type names have no identifier. This is already validated by - // the parser. - assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); - - QualType T = GetTypeForDeclarator(D, S); - - assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - - // In this context, we *do not* check D.getInvalidType(). If the declarator - // type was invalid, GetTypeForDeclarator() still returns a "valid" type, - // though it will not reflect the user specified type. - return T.getAsOpaquePtr(); -} - -// Called from Parser::ParseParenDeclarator(). -Sema::TypeResult Sema::ActOnParamDeclaratorType(Scope *S, Declarator &D) { - // Note: parameters have identifiers, but we don't care about them here, we - // just want the type converted. - QualType T = GetTypeForDeclarator(D, S); - - assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - - // In this context, we *do not* check D.getInvalidType(). If the declarator - // type was invalid, GetTypeForDeclarator() still returns a "valid" type, - // though it will not reflect the user specified type. - return T.getAsOpaquePtr(); -} - -AttributeList *Sema::ProcessTypeAttributes(QualType &Result, AttributeList *AL){ - // Scan through and apply attributes to this type where it makes sense. Some - // attributes (such as __address_space__, __vector_size__, etc) apply to the - // type, but others can be present in the type specifiers even though they - // apply to the decl. Here we apply and delete attributes that apply to the - // type and leave the others alone. - llvm::SmallVector LeftOverAttrs; - while (AL) { - // Unlink this attribute from the chain, so we can process it independently. - AttributeList *ThisAttr = AL; - AL = AL->getNext(); - ThisAttr->setNext(0); - - // If this is an attribute we can handle, do so now, otherwise, add it to - // the LeftOverAttrs list for rechaining. - switch (ThisAttr->getKind()) { - default: break; - case AttributeList::AT_address_space: - Result = HandleAddressSpaceTypeAttribute(Result, ThisAttr); - delete ThisAttr; // Consume the attribute. - continue; - } - - LeftOverAttrs.push_back(ThisAttr); - } - - // Rechain any attributes that haven't been deleted to the DeclSpec. - AttributeList *List = 0; - for (unsigned i = 0, e = LeftOverAttrs.size(); i != e; ++i) { - LeftOverAttrs[i]->setNext(List); - List = LeftOverAttrs[i]; - } - - return List; -} - -/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the -/// specified type. -QualType Sema::HandleAddressSpaceTypeAttribute(QualType Type, - AttributeList *Attr) { - // If this type is already address space qualified, reject it. - // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers - // for two or more different address spaces." - if (Type.getAddressSpace()) { - Diag(Attr->getLoc(), diag::err_attribute_address_multiple_qualifiers); - return Type; - } - - // Check the attribute arguments. - if (Attr->getNumArgs() != 1) { - Diag(Attr->getLoc(), diag::err_attribute_wrong_number_arguments, - std::string("1")); - return Type; - } - Expr *ASArgExpr = static_cast(Attr->getArg(0)); - llvm::APSInt addrSpace(32); - if (!ASArgExpr->isIntegerConstantExpr(addrSpace, Context)) { - Diag(Attr->getLoc(), diag::err_attribute_address_space_not_int, - ASArgExpr->getSourceRange()); - return Type; - } - - unsigned ASIdx = static_cast(addrSpace.getZExtValue()); - return Context.getASQualType(Type, ASIdx); -} - diff --git a/clang/Sema/SemaUtil.h b/clang/Sema/SemaUtil.h deleted file mode 100644 index 35452b18e6f..00000000000 --- a/clang/Sema/SemaUtil.h +++ /dev/null @@ -1,35 +0,0 @@ -//===--- SemaUtil.h - Utility functions for semantic analysis -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides a few static inline functions that are useful for -// performing semantic analysis. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_UTIL_H -#define LLVM_CLANG_SEMA_UTIL_H - -#include "clang/AST/Expr.h" - -namespace clang { - -/// Utility method to determine if a CallExpr is a call to a builtin. -static inline bool isCallBuiltin(CallExpr* cexp) { - Expr* sub = cexp->getCallee()->IgnoreParenCasts(); - - if (DeclRefExpr* E = dyn_cast(sub)) - if (E->getDecl()->getIdentifier()->getBuiltinID() > 0) - return true; - - return false; -} - -} // end namespace clang - -#endif diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index d0b9f6b8178..63d76a716ab 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/clang.xcodeproj/project.pbxproj @@ -236,17 +236,17 @@ /* Begin PBXFileReference section */ 03F50AC50D416EAA00B9CF60 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Targets.cpp; sourceTree = ""; }; 1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = ""; }; - 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = CodeGen/CGExprConstant.cpp; sourceTree = ""; }; + 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = ""; }; 1A68BC110D0CADDD001A28C8 /* PPCBuiltins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = PPCBuiltins.def; path = clang/AST/PPCBuiltins.def; sourceTree = ""; }; 1A68BC120D0CADDD001A28C8 /* TargetBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetBuiltins.h; path = clang/AST/TargetBuiltins.h; sourceTree = ""; }; 1A68BC130D0CADDD001A28C8 /* X86Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = X86Builtins.def; path = clang/AST/X86Builtins.def; sourceTree = ""; }; 1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = ""; tabWidth = 2; }; - 1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = CodeGen/CGObjC.cpp; sourceTree = ""; }; + 1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = ""; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = ""; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = ""; }; - 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = ""; }; - 3513185F0CD14468006B66F7 /* DeclSerialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSerialization.cpp; path = AST/DeclSerialization.cpp; sourceTree = ""; }; - 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = ""; }; + 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = ""; }; + 3513185F0CD14468006B66F7 /* DeclSerialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSerialization.cpp; path = lib/AST/DeclSerialization.cpp; sourceTree = ""; }; + 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = lib/AST/ExprCXX.cpp; sourceTree = ""; }; 352981080CC58344008B5E84 /* SerializationTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SerializationTest.cpp; path = Driver/SerializationTest.cpp; sourceTree = ""; }; 352C19DC0CA321C80045DB98 /* CFGRecStmtDeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGRecStmtDeclVisitor.h; path = clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h; sourceTree = ""; }; 352C19DD0CA321C80045DB98 /* CFGRecStmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGRecStmtVisitor.h; path = clang/Analysis/Visitors/CFGRecStmtVisitor.h; sourceTree = ""; }; @@ -254,65 +254,64 @@ 352C19DF0CA321C80045DB98 /* CFGVarDeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGVarDeclVisitor.h; path = clang/Analysis/Visitors/CFGVarDeclVisitor.h; sourceTree = ""; }; 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = ""; }; 355CF6820C90A8B600A08AA3 /* LocalCheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalCheckers.h; path = clang/Analysis/LocalCheckers.h; sourceTree = ""; }; - 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = ""; }; + 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = lib/Analysis/LiveVariables.cpp; sourceTree = ""; }; 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SourceLocation.cpp; sourceTree = ""; }; 3580CC0B0D072E5C00C5E4F4 /* LangOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LangOptions.cpp; sourceTree = ""; }; - 35839B090CDF845F006ED061 /* StmtSerialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtSerialization.cpp; path = AST/StmtSerialization.cpp; sourceTree = ""; }; - 35839B0A0CDF845F006ED061 /* TypeSerialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeSerialization.cpp; path = AST/TypeSerialization.cpp; sourceTree = ""; }; + 35839B090CDF845F006ED061 /* StmtSerialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtSerialization.cpp; path = lib/AST/StmtSerialization.cpp; sourceTree = ""; }; + 35839B0A0CDF845F006ED061 /* TypeSerialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeSerialization.cpp; path = lib/AST/TypeSerialization.cpp; sourceTree = ""; }; 35847BE30CC7DB9000C40FFF /* StmtIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtIterator.h; path = clang/AST/StmtIterator.h; sourceTree = ""; }; - 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtIterator.cpp; path = AST/StmtIterator.cpp; sourceTree = ""; }; - 35A2B8610CF8FFA300E6C317 /* SemaUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaUtil.h; path = Sema/SemaUtil.h; sourceTree = ""; }; + 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtIterator.cpp; path = lib/AST/StmtIterator.cpp; sourceTree = ""; }; + 35A2B8610CF8FFA300E6C317 /* SemaUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaUtil.h; path = lib/Sema/SemaUtil.h; sourceTree = ""; }; 35BB2D7A0D1994FA00944DB5 /* TranslationUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TranslationUnit.h; path = clang/AST/TranslationUnit.h; sourceTree = ""; }; - 35BB2D7C0D19951A00944DB5 /* TranslationUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TranslationUnit.cpp; path = AST/TranslationUnit.cpp; sourceTree = ""; }; - 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumer.cpp; path = AST/ASTConsumer.cpp; sourceTree = ""; }; + 35BB2D7C0D19951A00944DB5 /* TranslationUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TranslationUnit.cpp; path = lib/AST/TranslationUnit.cpp; sourceTree = ""; }; + 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumer.cpp; path = lib/AST/ASTConsumer.cpp; sourceTree = ""; }; 35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTConsumer.h; path = clang/AST/ASTConsumer.h; sourceTree = ""; }; - 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtViz.cpp; path = AST/StmtViz.cpp; sourceTree = ""; }; + 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StmtViz.cpp; path = lib/AST/StmtViz.cpp; sourceTree = ""; }; 35CFFE010CA1CBDD00E6F2BE /* StmtGraphTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtGraphTraits.h; path = clang/AST/StmtGraphTraits.h; sourceTree = ""; }; 35D1DDD10CA9C6D50096E967 /* DataflowSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowSolver.h; path = clang/Analysis/FlowSensitive/DataflowSolver.h; sourceTree = ""; }; 35D1DDD20CA9C6D50096E967 /* DataflowValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowValues.h; path = clang/Analysis/FlowSensitive/DataflowValues.h; sourceTree = ""; }; - 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicValueFactory.cpp; path = Analysis/BasicValueFactory.cpp; sourceTree = ""; }; - 35D55B250D81D8C60092E734 /* CFRefCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFRefCount.cpp; path = Analysis/CFRefCount.cpp; sourceTree = ""; }; - 35D55B260D81D8C60092E734 /* CFRefCount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFRefCount.h; path = Analysis/CFRefCount.h; sourceTree = ""; }; + 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicValueFactory.cpp; path = lib/Analysis/BasicValueFactory.cpp; sourceTree = ""; }; + 35D55B250D81D8C60092E734 /* CFRefCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CFRefCount.cpp; path = lib/Analysis/CFRefCount.cpp; sourceTree = ""; }; 35D55B290D81D8E50092E734 /* BasicValueFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BasicValueFactory.h; path = clang/Analysis/PathSensitive/BasicValueFactory.h; sourceTree = ""; }; 35F9B1530D1C6ADF00DDFDAE /* ExprDeclBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExprDeclBitVector.h; path = clang/Analysis/Support/ExprDeclBitVector.h; sourceTree = ""; }; 35F9B1550D1C6B2E00DDFDAE /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/Analyses/LiveVariables.h; sourceTree = ""; }; 35F9B1560D1C6B2E00DDFDAE /* UninitializedValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UninitializedValues.h; path = clang/Analysis/Analyses/UninitializedValues.h; sourceTree = ""; }; 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = ""; }; - 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = ""; }; + 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = lib/Parse/AttributeList.cpp; sourceTree = ""; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = ""; }; 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = ""; }; - DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = Parse/ParseExprCXX.cpp; sourceTree = ""; }; + DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = ""; }; DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = ""; }; DE06BECA0A854E4B0050E87E /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Parse/Scope.h; sourceTree = ""; }; - DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = Parse/Parser.cpp; sourceTree = ""; }; + DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = lib/Parse/Parser.cpp; sourceTree = ""; }; DE06E8130A8FF9330050E87E /* Action.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Parse/Action.h; sourceTree = ""; tabWidth = 8; usesTabs = 0; }; DE0FCA620A95859D00248FD5 /* Expr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Expr.h; path = clang/AST/Expr.h; sourceTree = ""; }; - DE0FCB330A9C21F100248FD5 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Expr.cpp; path = AST/Expr.cpp; sourceTree = ""; }; - DE1732FF0B068B700080B521 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTContext.cpp; path = AST/ASTContext.cpp; sourceTree = ""; }; - DE17336D0B068DC20080B521 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = Parse/DeclSpec.cpp; sourceTree = ""; }; + DE0FCB330A9C21F100248FD5 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Expr.cpp; path = lib/AST/Expr.cpp; sourceTree = ""; }; + DE1732FF0B068B700080B521 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTContext.cpp; path = lib/AST/ASTContext.cpp; sourceTree = ""; }; + DE17336D0B068DC20080B521 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = lib/Parse/DeclSpec.cpp; sourceTree = ""; }; DE17336F0B068DC60080B521 /* DeclSpec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DeclSpec.h; path = clang/Parse/DeclSpec.h; sourceTree = ""; }; DE1F22020A7D852A00FBF588 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Parser.h; path = clang/Parse/Parser.h; sourceTree = ""; }; - DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprComplex.cpp; path = CodeGen/CGExprComplex.cpp; sourceTree = ""; }; - DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprScalar.cpp; path = CodeGen/CGExprScalar.cpp; sourceTree = ""; }; - DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDeclCXX.cpp; path = Parse/ParseDeclCXX.cpp; sourceTree = ""; }; + DE224FF70C7AA98800D370A5 /* CGExprComplex.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprComplex.cpp; path = lib/CodeGen/CGExprComplex.cpp; sourceTree = ""; }; + DE22526F0C7E82D000D370A5 /* CGExprScalar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprScalar.cpp; path = lib/CodeGen/CGExprScalar.cpp; sourceTree = ""; }; + DE2255FB0C8004E600D370A5 /* ParseDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDeclCXX.cpp; path = lib/Parse/ParseDeclCXX.cpp; sourceTree = ""; }; DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HeaderSearch.h; sourceTree = ""; }; DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderSearch.cpp; sourceTree = ""; }; DE3450D60AEB543100DBC861 /* DirectoryLookup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DirectoryLookup.h; sourceTree = ""; }; - DE3452400AEF1A2D00DBC861 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Stmt.cpp; path = AST/Stmt.cpp; sourceTree = ""; }; + DE3452400AEF1A2D00DBC861 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Stmt.cpp; path = lib/AST/Stmt.cpp; sourceTree = ""; }; DE3452800AEF1B1800DBC861 /* Stmt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Stmt.h; path = clang/AST/Stmt.h; sourceTree = ""; }; DE345C190AFC658B00DBC861 /* StmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = StmtVisitor.h; path = clang/AST/StmtVisitor.h; sourceTree = ""; }; DE345F210AFD347900DBC861 /* StmtNodes.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = StmtNodes.def; path = clang/AST/StmtNodes.def; sourceTree = ""; }; - DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseObjc.cpp; path = Parse/ParseObjc.cpp; sourceTree = ""; }; - DE3460040AFDCC6500DBC861 /* ParseInit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseInit.cpp; path = Parse/ParseInit.cpp; sourceTree = ""; }; - DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseStmt.cpp; path = Parse/ParseStmt.cpp; sourceTree = ""; }; - DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDecl.cpp; path = Parse/ParseDecl.cpp; sourceTree = ""; }; - DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExpr.cpp; path = Parse/ParseExpr.cpp; sourceTree = ""; }; - DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MinimalAction.cpp; path = Parse/MinimalAction.cpp; sourceTree = ""; }; - DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtPrinter.cpp; path = AST/StmtPrinter.cpp; sourceTree = ""; }; + DE345FFF0AFDCC1900DBC861 /* ParseObjc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseObjc.cpp; path = lib/Parse/ParseObjc.cpp; sourceTree = ""; }; + DE3460040AFDCC6500DBC861 /* ParseInit.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseInit.cpp; path = lib/Parse/ParseInit.cpp; sourceTree = ""; }; + DE34600A0AFDCCBF00DBC861 /* ParseStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseStmt.cpp; path = lib/Parse/ParseStmt.cpp; sourceTree = ""; }; + DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDecl.cpp; path = lib/Parse/ParseDecl.cpp; sourceTree = ""; }; + DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExpr.cpp; path = lib/Parse/ParseExpr.cpp; sourceTree = ""; }; + DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = MinimalAction.cpp; path = lib/Parse/MinimalAction.cpp; sourceTree = ""; }; + DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtPrinter.cpp; path = lib/AST/StmtPrinter.cpp; sourceTree = ""; }; DE3464210B03040900DBC861 /* Type.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Type.h; path = clang/AST/Type.h; sourceTree = ""; }; - DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGObjCRuntime.h; path = CodeGen/CGObjCRuntime.h; sourceTree = ""; }; - DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjCGNU.cpp; path = CodeGen/CGObjCGNU.cpp; sourceTree = ""; }; + DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGObjCRuntime.h; path = lib/CodeGen/CGObjCRuntime.h; sourceTree = ""; }; + DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjCGNU.cpp; path = lib/CodeGen/CGObjCGNU.cpp; sourceTree = ""; }; DE3985780CB8ADC800223765 /* ASTConsumers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTConsumers.h; path = Driver/ASTConsumers.h; sourceTree = ""; }; DE39857A0CB8ADCB00223765 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = Driver/ASTConsumers.cpp; sourceTree = ""; }; DE3986EF0CB8D4B300223765 /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = ""; }; @@ -326,45 +325,45 @@ DE4121210D7F1BBE0080F80A /* GRExprEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRExprEngine.h; path = clang/Analysis/PathSensitive/GRExprEngine.h; sourceTree = ""; }; DE4121220D7F1BBE0080F80A /* GRTransferFuncs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRTransferFuncs.h; path = clang/Analysis/PathSensitive/GRTransferFuncs.h; sourceTree = ""; }; DE4121230D7F1BBE0080F80A /* GRCoreEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRCoreEngine.h; path = clang/Analysis/PathSensitive/GRCoreEngine.h; sourceTree = ""; }; - DE4121250D7F1C1C0080F80A /* ValueState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueState.cpp; path = Analysis/ValueState.cpp; sourceTree = ""; }; - DE4121260D7F1C1C0080F80A /* DeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeadStores.cpp; path = Analysis/DeadStores.cpp; sourceTree = ""; }; - DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolManager.cpp; path = Analysis/SymbolManager.cpp; sourceTree = ""; }; - DE4121280D7F1C1C0080F80A /* ExplodedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExplodedGraph.cpp; path = Analysis/ExplodedGraph.cpp; sourceTree = ""; }; - DE4121290D7F1C1C0080F80A /* UninitializedValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UninitializedValues.cpp; path = Analysis/UninitializedValues.cpp; sourceTree = ""; }; - DE41212A0D7F1C1C0080F80A /* GRCoreEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRCoreEngine.cpp; path = Analysis/GRCoreEngine.cpp; sourceTree = ""; }; - DE41212C0D7F1C1C0080F80A /* GRSimpleVals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRSimpleVals.h; path = Analysis/GRSimpleVals.h; sourceTree = ""; }; - DE41212D0D7F1C1C0080F80A /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = ""; }; - DE41212E0D7F1C1C0080F80A /* RValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RValues.cpp; path = Analysis/RValues.cpp; sourceTree = ""; }; - DE41212F0D7F1C1C0080F80A /* GRSimpleVals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRSimpleVals.cpp; path = Analysis/GRSimpleVals.cpp; sourceTree = ""; }; - DE4121300D7F1C1C0080F80A /* GRBlockCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRBlockCounter.cpp; path = Analysis/GRBlockCounter.cpp; sourceTree = ""; }; - DE4121310D7F1C1C0080F80A /* GRExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRExprEngine.cpp; path = Analysis/GRExprEngine.cpp; sourceTree = ""; }; - DE4121320D7F1C1C0080F80A /* ProgramPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProgramPoint.cpp; path = Analysis/ProgramPoint.cpp; sourceTree = ""; }; - DE4264FB0C113592005A861D /* CGDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGDecl.cpp; path = CodeGen/CGDecl.cpp; sourceTree = ""; }; + DE4121250D7F1C1C0080F80A /* ValueState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueState.cpp; path = lib/Analysis/ValueState.cpp; sourceTree = ""; }; + DE4121260D7F1C1C0080F80A /* DeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeadStores.cpp; path = lib/Analysis/DeadStores.cpp; sourceTree = ""; }; + DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolManager.cpp; path = lib/Analysis/SymbolManager.cpp; sourceTree = ""; }; + DE4121280D7F1C1C0080F80A /* ExplodedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExplodedGraph.cpp; path = lib/Analysis/ExplodedGraph.cpp; sourceTree = ""; }; + DE4121290D7F1C1C0080F80A /* UninitializedValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UninitializedValues.cpp; path = lib/Analysis/UninitializedValues.cpp; sourceTree = ""; }; + DE41212A0D7F1C1C0080F80A /* GRCoreEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRCoreEngine.cpp; path = lib/Analysis/GRCoreEngine.cpp; sourceTree = ""; }; + DE41212C0D7F1C1C0080F80A /* GRSimpleVals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRSimpleVals.h; path = lib/Analysis/GRSimpleVals.h; sourceTree = ""; }; + DE41212D0D7F1C1C0080F80A /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = lib/Analysis/LiveVariables.cpp; sourceTree = ""; }; + DE41212E0D7F1C1C0080F80A /* RValues.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RValues.cpp; path = lib/Analysis/RValues.cpp; sourceTree = ""; }; + DE41212F0D7F1C1C0080F80A /* GRSimpleVals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRSimpleVals.cpp; path = lib/Analysis/GRSimpleVals.cpp; sourceTree = ""; }; + DE4121300D7F1C1C0080F80A /* GRBlockCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRBlockCounter.cpp; path = lib/Analysis/GRBlockCounter.cpp; sourceTree = ""; }; + DE4121310D7F1C1C0080F80A /* GRExprEngine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRExprEngine.cpp; path = lib/Analysis/GRExprEngine.cpp; sourceTree = ""; }; + DE4121320D7F1C1C0080F80A /* ProgramPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProgramPoint.cpp; path = lib/Analysis/ProgramPoint.cpp; sourceTree = ""; }; + DE4264FB0C113592005A861D /* CGDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGDecl.cpp; path = lib/CodeGen/CGDecl.cpp; sourceTree = ""; }; DE46BF270AE0A82D00CC047C /* TargetInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TargetInfo.h; sourceTree = ""; }; - DE4772F90C10EAE5002239E8 /* CGStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGStmt.cpp; path = CodeGen/CGStmt.cpp; sourceTree = ""; }; - DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExpr.cpp; path = CodeGen/CGExpr.cpp; sourceTree = ""; }; - DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprObjC.cpp; path = Sema/SemaExprObjC.cpp; sourceTree = ""; }; + DE4772F90C10EAE5002239E8 /* CGStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGStmt.cpp; path = lib/CodeGen/CGStmt.cpp; sourceTree = ""; }; + DE4772FB0C10EAEC002239E8 /* CGExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExpr.cpp; path = lib/CodeGen/CGExpr.cpp; sourceTree = ""; }; + DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprObjC.cpp; path = lib/Sema/SemaExprObjC.cpp; sourceTree = ""; }; DE53370B0CE2D96F00D9A028 /* RewriteRope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RewriteRope.h; path = clang/Rewrite/RewriteRope.h; sourceTree = ""; }; DE5932CD0AD60FF400BC794C /* clang.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = clang.cpp; path = Driver/clang.cpp; sourceTree = ""; }; DE5932CE0AD60FF400BC794C /* clang.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = clang.h; path = Driver/clang.h; sourceTree = ""; }; DE5932CF0AD60FF400BC794C /* PrintParserCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PrintParserCallbacks.cpp; path = Driver/PrintParserCallbacks.cpp; sourceTree = ""; }; DE5932D00AD60FF400BC794C /* PrintPreprocessedOutput.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PrintPreprocessedOutput.cpp; path = Driver/PrintPreprocessedOutput.cpp; sourceTree = ""; }; - DE67E70A0C020EC500F66BC5 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = Sema/SemaType.cpp; sourceTree = ""; }; - DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaStmt.cpp; path = Sema/SemaStmt.cpp; sourceTree = ""; }; - DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprCXX.cpp; path = Sema/SemaExprCXX.cpp; sourceTree = ""; }; - DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExpr.cpp; path = Sema/SemaExpr.cpp; sourceTree = ""; }; - DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDecl.cpp; path = Sema/SemaDecl.cpp; sourceTree = ""; tabWidth = 8; usesTabs = 0; }; - DE67E7140C020EDF00F66BC5 /* Sema.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Sema.h; path = Sema/Sema.h; sourceTree = ""; }; - DE67E7160C020EE400F66BC5 /* Sema.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Sema.cpp; path = Sema/Sema.cpp; sourceTree = ""; }; - DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseAST.cpp; path = Sema/ParseAST.cpp; sourceTree = ""; }; + DE67E70A0C020EC500F66BC5 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = lib/Sema/SemaType.cpp; sourceTree = ""; }; + DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaStmt.cpp; path = lib/Sema/SemaStmt.cpp; sourceTree = ""; }; + DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExprCXX.cpp; path = lib/Sema/SemaExprCXX.cpp; sourceTree = ""; }; + DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExpr.cpp; path = lib/Sema/SemaExpr.cpp; sourceTree = ""; }; + DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDecl.cpp; path = lib/Sema/SemaDecl.cpp; sourceTree = ""; tabWidth = 8; usesTabs = 0; }; + DE67E7140C020EDF00F66BC5 /* Sema.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Sema.h; path = lib/Sema/Sema.h; sourceTree = ""; }; + DE67E7160C020EE400F66BC5 /* Sema.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Sema.cpp; path = lib/Sema/Sema.cpp; sourceTree = ""; }; + DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseAST.cpp; path = lib/Sema/ParseAST.cpp; sourceTree = ""; }; DE67E7270C02109800F66BC5 /* ParseAST.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ParseAST.h; path = clang/Sema/ParseAST.h; sourceTree = ""; }; DE6951C60C4D1F5D00A5826B /* RecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = RecordLayout.h; path = clang/AST/RecordLayout.h; sourceTree = ""; }; DE6954630C5121BD00A5826B /* Token.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Token.h; sourceTree = ""; }; - DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclObjC.cpp; path = Sema/SemaDeclObjC.cpp; sourceTree = ""; }; + DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclObjC.cpp; path = lib/Sema/SemaDeclObjC.cpp; sourceTree = ""; }; DE704BD10D1647E7009C7762 /* HeaderMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeaderMap.h; sourceTree = ""; }; DE704DD10D1668A4009C7762 /* HeaderMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderMap.cpp; sourceTree = ""; }; DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = ""; }; - DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = AST/Type.cpp; sourceTree = ""; }; + DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = lib/AST/Type.cpp; sourceTree = ""; }; DE85CD800D8380B10070E26E /* TokenLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenLexer.cpp; sourceTree = ""; }; DE85CD840D8380F20070E26E /* TokenLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenLexer.h; sourceTree = ""; }; DE85CD9E0D8382DD0070E26E /* MacroArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroArgs.h; sourceTree = ""; }; @@ -372,27 +371,27 @@ DE85CDAB0D838C120070E26E /* PPMacroExpansion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPMacroExpansion.cpp; sourceTree = ""; }; DE85CDAF0D838C390070E26E /* PPDirectives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPDirectives.cpp; sourceTree = ""; }; DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPLexerChange.cpp; sourceTree = ""; }; - DE928B120C05659200231DA4 /* ModuleBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleBuilder.cpp; path = CodeGen/ModuleBuilder.cpp; sourceTree = ""; }; + DE928B120C05659200231DA4 /* ModuleBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleBuilder.cpp; path = lib/CodeGen/ModuleBuilder.cpp; sourceTree = ""; }; DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ModuleBuilder.h; path = clang/CodeGen/ModuleBuilder.h; sourceTree = ""; }; - DE928B7C0C0A615100231DA4 /* CodeGenModule.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenModule.h; path = CodeGen/CodeGenModule.h; sourceTree = ""; }; - DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenModule.cpp; path = CodeGen/CodeGenModule.cpp; sourceTree = ""; }; - DE928B800C0A615B00231DA4 /* CodeGenFunction.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenFunction.h; path = CodeGen/CodeGenFunction.h; sourceTree = ""; }; - DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenFunction.cpp; path = CodeGen/CodeGenFunction.cpp; sourceTree = ""; }; + DE928B7C0C0A615100231DA4 /* CodeGenModule.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenModule.h; path = lib/CodeGen/CodeGenModule.h; sourceTree = ""; }; + DE928B7E0C0A615600231DA4 /* CodeGenModule.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenModule.cpp; path = lib/CodeGen/CodeGenModule.cpp; sourceTree = ""; }; + DE928B800C0A615B00231DA4 /* CodeGenFunction.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenFunction.h; path = lib/CodeGen/CodeGenFunction.h; sourceTree = ""; }; + DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenFunction.cpp; path = lib/CodeGen/CodeGenFunction.cpp; sourceTree = ""; }; DEA977890CBE87EB00F872F9 /* RewriteTest.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteTest.cpp; path = Driver/RewriteTest.cpp; sourceTree = ""; }; DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = ""; }; DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = ""; }; DEB0AEB80C2087A700718A22 /* TextDiagnostics.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnostics.h; path = Driver/TextDiagnostics.h; sourceTree = ""; }; DEB0AEBA0C2087AB00718A22 /* TextDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnostics.cpp; path = Driver/TextDiagnostics.cpp; sourceTree = ""; }; - DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = AST/CFG.cpp; sourceTree = ""; }; + DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = lib/AST/CFG.cpp; sourceTree = ""; }; DEC63B1B0C7B940600DBF169 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/AST/CFG.h; sourceTree = ""; }; - DEC82DC30C32D50A00BAC245 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = Driver/DiagChecker.cpp; sourceTree = ""; }; + DEC82DC30C32D50A00BAC245 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = lib/Driver/DiagChecker.cpp; sourceTree = ""; }; DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = ""; }; DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = ""; }; DED626C80AE0C065001E80A4 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TargetInfo.cpp; sourceTree = ""; }; - DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Decl.cpp; path = AST/Decl.cpp; sourceTree = ""; tabWidth = 8; usesTabs = 0; }; + DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Decl.cpp; path = lib/AST/Decl.cpp; sourceTree = ""; tabWidth = 8; usesTabs = 0; }; DED676D00B6C786700AAD4A3 /* Builtins.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = Builtins.def; path = clang/AST/Builtins.def; sourceTree = ""; }; DED676F90B6C797B00AAD4A3 /* Builtins.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Builtins.h; path = clang/AST/Builtins.h; sourceTree = ""; }; - DED677C80B6C854100AAD4A3 /* Builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Builtins.cpp; path = AST/Builtins.cpp; sourceTree = ""; }; + DED677C80B6C854100AAD4A3 /* Builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Builtins.cpp; path = lib/AST/Builtins.cpp; sourceTree = ""; }; DED7D7310A524295003AD0FB /* Diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Diagnostic.h; sourceTree = ""; }; DED7D7320A524295003AD0FB /* DiagnosticKinds.def */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = DiagnosticKinds.def; sourceTree = ""; }; DED7D7330A524295003AD0FB /* FileManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FileManager.h; sourceTree = ""; }; @@ -417,16 +416,16 @@ DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = ""; }; DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = ""; }; DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = ""; }; - DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenTypes.h; path = CodeGen/CodeGenTypes.h; sourceTree = ""; }; - DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenTypes.cpp; path = CodeGen/CodeGenTypes.cpp; sourceTree = ""; }; + DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CodeGenTypes.h; path = lib/CodeGen/CodeGenTypes.h; sourceTree = ""; }; + DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenTypes.cpp; path = lib/CodeGen/CodeGenTypes.cpp; sourceTree = ""; }; DEEBCBE20C33702C00A9FE82 /* TextDiagnosticBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticBuffer.h; path = Driver/TextDiagnosticBuffer.h; sourceTree = ""; }; DEEBCBE40C33703100A9FE82 /* TextDiagnosticBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticBuffer.cpp; path = Driver/TextDiagnosticBuffer.cpp; sourceTree = ""; }; DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = ""; }; - DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = AST/StmtDumper.cpp; sourceTree = ""; }; - DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprAgg.cpp; path = CodeGen/CGExprAgg.cpp; sourceTree = ""; }; - DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaChecking.cpp; path = Sema/SemaChecking.cpp; sourceTree = ""; }; + DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = lib/AST/StmtDumper.cpp; sourceTree = ""; }; + DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprAgg.cpp; path = lib/CodeGen/CGExprAgg.cpp; sourceTree = ""; }; + DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SemaChecking.cpp; path = lib/Sema/SemaChecking.cpp; sourceTree = ""; }; DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Rewriter.h; path = clang/Rewrite/Rewriter.h; sourceTree = ""; }; - DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Rewriter.cpp; path = Rewrite/Rewriter.cpp; sourceTree = ""; }; + DEF7D9F80C9C8B1D0001F598 /* Rewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Rewriter.cpp; path = lib/Rewrite/Rewriter.cpp; sourceTree = ""; }; F0226FD00C18084500141F42 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = Driver/TextDiagnosticPrinter.cpp; sourceTree = ""; }; F0226FD10C18084500141F42 /* TextDiagnosticPrinter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TextDiagnosticPrinter.h; path = Driver/TextDiagnosticPrinter.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -506,7 +505,6 @@ children = ( 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */, 35D55B250D81D8C60092E734 /* CFRefCount.cpp */, - 35D55B260D81D8C60092E734 /* CFRefCount.h */, 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */, DE4121250D7F1C1C0080F80A /* ValueState.cpp */, DE4121260D7F1C1C0080F80A /* DeadStores.cpp */, @@ -812,7 +810,8 @@ DED626C80AE0C065001E80A4 /* TargetInfo.cpp */, DED7D76E0A5242C7003AD0FB /* TokenKinds.cpp */, ); - path = Basic; + name = Basic; + path = lib/Basic; sourceTree = ""; }; DED7D78C0A5242E6003AD0FB /* Lex */ = { @@ -834,7 +833,8 @@ DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */, DE85CD800D8380B10070E26E /* TokenLexer.cpp */, ); - path = Lex; + name = Lex; + path = lib/Lex; sourceTree = ""; }; DEF7D9F40C9C8B020001F598 /* Rewrite */ = { diff --git a/clang/lib/AST/ASTConsumer.cpp b/clang/lib/AST/ASTConsumer.cpp new file mode 100644 index 00000000000..b3d12710927 --- /dev/null +++ b/clang/lib/AST/ASTConsumer.cpp @@ -0,0 +1,28 @@ +//===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- 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 ASTConsumer class. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/Decl.h" +using namespace clang; + +ASTConsumer::~ASTConsumer() {} + +void ASTConsumer::HandleTopLevelDeclaration(Decl* d) { + if (ScopedDecl* sd = dyn_cast(d)) + while (sd) { + HandleTopLevelDecl(sd); + sd = sd->getNextDeclarator(); + } + else + HandleTopLevelDecl(d); +} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp new file mode 100644 index 00000000000..db4d53aa481 --- /dev/null +++ b/clang/lib/AST/ASTContext.cpp @@ -0,0 +1,1853 @@ +//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ASTContext interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +enum FloatingRank { + FloatRank, DoubleRank, LongDoubleRank +}; + +ASTContext::~ASTContext() { + // Deallocate all the types. + while (!Types.empty()) { + if (FunctionTypeProto *FT = dyn_cast(Types.back())) { + // Destroy the object, but don't call delete. These are malloc'd. + FT->~FunctionTypeProto(); + free(FT); + } else { + delete Types.back(); + } + Types.pop_back(); + } +} + +void ASTContext::PrintStats() const { + fprintf(stderr, "*** AST Context Stats:\n"); + fprintf(stderr, " %d types total.\n", (int)Types.size()); + unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0; + unsigned NumVector = 0, NumComplex = 0; + unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0; + + unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0; + unsigned NumObjCInterfaces = 0, NumObjCQualifiedInterfaces = 0; + unsigned NumObjCQualifiedIds = 0; + + for (unsigned i = 0, e = Types.size(); i != e; ++i) { + Type *T = Types[i]; + if (isa(T)) + ++NumBuiltin; + else if (isa(T)) + ++NumPointer; + else if (isa(T)) + ++NumReference; + else if (isa(T)) + ++NumComplex; + else if (isa(T)) + ++NumArray; + else if (isa(T)) + ++NumVector; + else if (isa(T)) + ++NumFunctionNP; + else if (isa(T)) + ++NumFunctionP; + else if (isa(T)) + ++NumTypeName; + else if (TagType *TT = dyn_cast(T)) { + ++NumTagged; + switch (TT->getDecl()->getKind()) { + default: assert(0 && "Unknown tagged type!"); + case Decl::Struct: ++NumTagStruct; break; + case Decl::Union: ++NumTagUnion; break; + case Decl::Class: ++NumTagClass; break; + case Decl::Enum: ++NumTagEnum; break; + } + } else if (isa(T)) + ++NumObjCInterfaces; + else if (isa(T)) + ++NumObjCQualifiedInterfaces; + else if (isa(T)) + ++NumObjCQualifiedIds; + else { + QualType(T, 0).dump(); + assert(0 && "Unknown type!"); + } + } + + fprintf(stderr, " %d builtin types\n", NumBuiltin); + fprintf(stderr, " %d pointer types\n", NumPointer); + fprintf(stderr, " %d reference types\n", NumReference); + fprintf(stderr, " %d complex types\n", NumComplex); + fprintf(stderr, " %d array types\n", NumArray); + fprintf(stderr, " %d vector types\n", NumVector); + fprintf(stderr, " %d function types with proto\n", NumFunctionP); + fprintf(stderr, " %d function types with no proto\n", NumFunctionNP); + fprintf(stderr, " %d typename (typedef) types\n", NumTypeName); + fprintf(stderr, " %d tagged types\n", NumTagged); + fprintf(stderr, " %d struct types\n", NumTagStruct); + fprintf(stderr, " %d union types\n", NumTagUnion); + fprintf(stderr, " %d class types\n", NumTagClass); + fprintf(stderr, " %d enum types\n", NumTagEnum); + fprintf(stderr, " %d interface types\n", NumObjCInterfaces); + fprintf(stderr, " %d protocol qualified interface types\n", + NumObjCQualifiedInterfaces); + fprintf(stderr, " %d protocol qualified id types\n", + NumObjCQualifiedIds); + fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+ + NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+ + NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+ + NumFunctionP*sizeof(FunctionTypeProto)+ + NumFunctionNP*sizeof(FunctionTypeNoProto)+ + NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType))); +} + + +void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { + Types.push_back((R = QualType(new BuiltinType(K),0)).getTypePtr()); +} + +void ASTContext::InitBuiltinTypes() { + assert(VoidTy.isNull() && "Context reinitialized?"); + + // C99 6.2.5p19. + InitBuiltinType(VoidTy, BuiltinType::Void); + + // C99 6.2.5p2. + InitBuiltinType(BoolTy, BuiltinType::Bool); + // C99 6.2.5p3. + if (Target.isCharSigned()) + InitBuiltinType(CharTy, BuiltinType::Char_S); + else + InitBuiltinType(CharTy, BuiltinType::Char_U); + // C99 6.2.5p4. + InitBuiltinType(SignedCharTy, BuiltinType::SChar); + InitBuiltinType(ShortTy, BuiltinType::Short); + InitBuiltinType(IntTy, BuiltinType::Int); + InitBuiltinType(LongTy, BuiltinType::Long); + InitBuiltinType(LongLongTy, BuiltinType::LongLong); + + // C99 6.2.5p6. + InitBuiltinType(UnsignedCharTy, BuiltinType::UChar); + InitBuiltinType(UnsignedShortTy, BuiltinType::UShort); + InitBuiltinType(UnsignedIntTy, BuiltinType::UInt); + InitBuiltinType(UnsignedLongTy, BuiltinType::ULong); + InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong); + + // C99 6.2.5p10. + InitBuiltinType(FloatTy, BuiltinType::Float); + InitBuiltinType(DoubleTy, BuiltinType::Double); + InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble); + + // C99 6.2.5p11. + FloatComplexTy = getComplexType(FloatTy); + DoubleComplexTy = getComplexType(DoubleTy); + LongDoubleComplexTy = getComplexType(LongDoubleTy); + + BuiltinVaListType = QualType(); + ObjCIdType = QualType(); + IdStructType = 0; + ObjCClassType = QualType(); + ClassStructType = 0; + + ObjCConstantStringType = QualType(); + + // void * type + VoidPtrTy = getPointerType(VoidTy); +} + +//===----------------------------------------------------------------------===// +// Type Sizing and Analysis +//===----------------------------------------------------------------------===// + +/// getTypeSize - Return the size of the specified type, in bits. This method +/// does not work on incomplete types. +std::pair +ASTContext::getTypeInfo(QualType T) { + T = T.getCanonicalType(); + uint64_t Width; + unsigned Align; + switch (T->getTypeClass()) { + case Type::TypeName: assert(0 && "Not a canonical type!"); + case Type::FunctionNoProto: + case Type::FunctionProto: + default: + assert(0 && "Incomplete types have no size!"); + case Type::VariableArray: + assert(0 && "VLAs not implemented yet!"); + case Type::ConstantArray: { + ConstantArrayType *CAT = cast(T); + + std::pair EltInfo = getTypeInfo(CAT->getElementType()); + Width = EltInfo.first*CAT->getSize().getZExtValue(); + Align = EltInfo.second; + break; + } + case Type::OCUVector: + case Type::Vector: { + std::pair EltInfo = + getTypeInfo(cast(T)->getElementType()); + Width = EltInfo.first*cast(T)->getNumElements(); + // FIXME: Vector alignment is not the alignment of its elements. + Align = EltInfo.second; + break; + } + + case Type::Builtin: + // FIXME: need to use TargetInfo to derive the target specific sizes. This + // implementation will suffice for play with vector support. + switch (cast(T)->getKind()) { + default: assert(0 && "Unknown builtin type!"); + case BuiltinType::Void: + assert(0 && "Incomplete types have no size!"); + case BuiltinType::Bool: + Width = Target.getBoolWidth(); + Align = Target.getBoolAlign(); + break; + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::SChar: + Width = Target.getCharWidth(); + Align = Target.getCharAlign(); + break; + case BuiltinType::UShort: + case BuiltinType::Short: + Width = Target.getShortWidth(); + Align = Target.getShortAlign(); + break; + case BuiltinType::UInt: + case BuiltinType::Int: + Width = Target.getIntWidth(); + Align = Target.getIntAlign(); + break; + case BuiltinType::ULong: + case BuiltinType::Long: + Width = Target.getLongWidth(); + Align = Target.getLongAlign(); + break; + case BuiltinType::ULongLong: + case BuiltinType::LongLong: + Width = Target.getLongLongWidth(); + Align = Target.getLongLongAlign(); + break; + case BuiltinType::Float: + Width = Target.getFloatWidth(); + Align = Target.getFloatAlign(); + break; + case BuiltinType::Double: + Width = Target.getDoubleWidth(); + Align = Target.getDoubleAlign(); + break; + case BuiltinType::LongDouble: + Width = Target.getLongDoubleWidth(); + Align = Target.getLongDoubleAlign(); + break; + } + break; + case Type::ASQual: + // FIXME: Pointers into different addr spaces could have different sizes and + // alignment requirements: getPointerInfo should take an AddrSpace. + return getTypeInfo(QualType(cast(T)->getBaseType(), 0)); + case Type::ObjCQualifiedId: + Width = Target.getPointerWidth(0); + Align = Target.getPointerAlign(0); + break; + case Type::Pointer: { + unsigned AS = cast(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::Reference: + // "When applied to a reference or a reference type, the result is the size + // of the referenced type." C++98 5.3.3p2: expr.sizeof. + // FIXME: This is wrong for struct layout: a reference in a struct has + // pointer size. + return getTypeInfo(cast(T)->getReferenceeType()); + + case Type::Complex: { + // Complex types have the same alignment as their elements, but twice the + // size. + std::pair EltInfo = + getTypeInfo(cast(T)->getElementType()); + Width = EltInfo.first*2; + Align = EltInfo.second; + break; + } + case Type::Tagged: + TagType *TT = cast(T); + if (RecordType *RT = dyn_cast(TT)) { + const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); + Width = Layout.getSize(); + Align = Layout.getAlignment(); + } else if (EnumDecl *ED = dyn_cast(TT->getDecl())) { + return getTypeInfo(ED->getIntegerType()); + } else { + assert(0 && "Unimplemented type sizes!"); + } + break; + } + + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); + return std::make_pair(Width, Align); +} + +/// getASTRecordLayout - Get or compute information about the layout of the +/// specified record (struct/union/class), which indicates its size and field +/// position information. +const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { + assert(D->isDefinition() && "Cannot get layout of forward declarations!"); + + // Look up this layout, if already laid out, return what we have. + const ASTRecordLayout *&Entry = ASTRecordLayouts[D]; + if (Entry) return *Entry; + + // Allocate and assign into ASTRecordLayouts here. The "Entry" reference can + // be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into. + ASTRecordLayout *NewEntry = new ASTRecordLayout(); + Entry = NewEntry; + + uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()]; + uint64_t RecordSize = 0; + unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits. + + if (D->getKind() != Decl::Union) { + if (const AlignedAttr *AA = D->getAttr()) + RecordAlign = std::max(RecordAlign, AA->getAlignment()); + + bool StructIsPacked = D->getAttr(); + + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { + const FieldDecl *FD = D->getMember(i); + bool FieldIsPacked = StructIsPacked || FD->getAttr(); + uint64_t FieldSize; + unsigned FieldAlign; + + if (const Expr *BitWidthExpr = FD->getBitWidth()) { + llvm::APSInt I(32); + bool BitWidthIsICE = + BitWidthExpr->isIntegerConstantExpr(I, *this); + assert (BitWidthIsICE && "Invalid BitField size expression"); + FieldSize = I.getZExtValue(); + + std::pair TypeInfo = getTypeInfo(FD->getType()); + uint64_t TypeSize = TypeInfo.first; + + if (const AlignedAttr *AA = FD->getAttr()) + FieldAlign = AA->getAlignment(); + else if (FieldIsPacked) + FieldAlign = 8; + else { + // FIXME: This is X86 specific, use 32-bit alignment for long long. + if (FD->getType()->isIntegerType() && TypeInfo.second > 32) + FieldAlign = 32; + else + FieldAlign = TypeInfo.second; + } + + // Check if we need to add padding to give the field the correct + // alignment. + if (RecordSize % FieldAlign + FieldSize > TypeSize) + RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); + + } else { + if (FD->getType()->isIncompleteType()) { + // This must be 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. + + if (const AlignedAttr *AA = FD->getAttr()) + FieldAlign = AA->getAlignment(); + else if (FieldIsPacked) + FieldAlign = 8; + else { + const ArrayType* ATy = FD->getType()->getAsArrayType(); + FieldAlign = getTypeAlign(ATy->getElementType()); + } + FieldSize = 0; + } else { + std::pair FieldInfo = getTypeInfo(FD->getType()); + FieldSize = FieldInfo.first; + + if (const AlignedAttr *AA = FD->getAttr()) + FieldAlign = AA->getAlignment(); + else if (FieldIsPacked) + FieldAlign = 8; + else + FieldAlign = FieldInfo.second; + } + + // Round up the current record size to the field's alignment boundary. + RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); + } + + // Place this field at the current location. + FieldOffsets[i] = RecordSize; + + // Reserve space for this field. + RecordSize += FieldSize; + + // Remember max struct/class alignment. + RecordAlign = std::max(RecordAlign, FieldAlign); + } + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1); + } else { + // Union layout just puts each member at the start of the record. + for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { + const FieldDecl *FD = D->getMember(i); + std::pair FieldInfo = getTypeInfo(FD->getType()); + uint64_t FieldSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + // FIXME: This is X86 specific, use 32-bit alignment for long long. + if (FD->getType()->isIntegerType() && FieldAlign > 32) + FieldAlign = 32; + + // Round up the current record size to the field's alignment boundary. + RecordSize = std::max(RecordSize, FieldSize); + + // Place this field at the start of the record. + FieldOffsets[i] = 0; + + // Remember max struct/class alignment. + RecordAlign = std::max(RecordAlign, FieldAlign); + } + } + + NewEntry->SetLayout(RecordSize, RecordAlign, FieldOffsets); + return *NewEntry; +} + +//===----------------------------------------------------------------------===// +// Type creation/memoization methods +//===----------------------------------------------------------------------===// + +QualType ASTContext::getASQualType(QualType T, unsigned AddressSpace) { + if (T.getCanonicalType().getAddressSpace() == AddressSpace) + return T; + + // Type's cannot have multiple ASQuals, therefore we know we only have to deal + // with CVR qualifiers from here on out. + assert(T.getCanonicalType().getAddressSpace() == 0 && + "Type is already address space qualified"); + + // Check if we've already instantiated an address space qual'd type of this + // type. + llvm::FoldingSetNodeID ID; + ASQualType::Profile(ID, T.getTypePtr(), AddressSpace); + void *InsertPos = 0; + if (ASQualType *ASQy = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ASQy, 0); + + // If the base type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getASQualType(T.getCanonicalType(), AddressSpace); + + // Get the new insert position for the node we care about. + ASQualType *NewIP = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + ASQualType *New = new ASQualType(T.getTypePtr(), Canonical, AddressSpace); + ASQualTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, T.getCVRQualifiers()); +} + + +/// getComplexType - Return the uniqued reference to the type for a complex +/// number with the specified element type. +QualType ASTContext::getComplexType(QualType T) { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + ComplexType::Profile(ID, T); + + void *InsertPos = 0; + if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(CT, 0); + + // If the pointee type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getComplexType(T.getCanonicalType()); + + // Get the new insert position for the node we care about. + ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + ComplexType *New = new ComplexType(T, Canonical); + Types.push_back(New); + ComplexTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + + +/// getPointerType - Return the uniqued reference to the type for a pointer to +/// the specified type. +QualType ASTContext::getPointerType(QualType T) { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + PointerType::Profile(ID, T); + + void *InsertPos = 0; + if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the pointee type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getPointerType(T.getCanonicalType()); + + // Get the new insert position for the node we care about. + PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + PointerType *New = new PointerType(T, Canonical); + Types.push_back(New); + PointerTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getReferenceType - Return the uniqued reference to the type for a reference +/// to the specified type. +QualType ASTContext::getReferenceType(QualType T) { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + ReferenceType::Profile(ID, T); + + void *InsertPos = 0; + if (ReferenceType *RT = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(RT, 0); + + // If the referencee type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getReferenceType(T.getCanonicalType()); + + // Get the new insert position for the node we care about. + ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + ReferenceType *New = new ReferenceType(T, Canonical); + Types.push_back(New); + ReferenceTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getConstantArrayType - Return the unique reference to the type for an +/// array of the specified element type. +QualType ASTContext::getConstantArrayType(QualType EltTy, + const llvm::APInt &ArySize, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + llvm::FoldingSetNodeID ID; + ConstantArrayType::Profile(ID, EltTy, ArySize); + + void *InsertPos = 0; + if (ConstantArrayType *ATP = + ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ATP, 0); + + // If the element type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!EltTy->isCanonical()) { + Canonical = getConstantArrayType(EltTy.getCanonicalType(), ArySize, + ASM, EltTypeQuals); + // Get the new insert position for the node we care about. + ConstantArrayType *NewIP = + ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + ConstantArrayType *New = new ConstantArrayType(EltTy, Canonical, ArySize, + ASM, EltTypeQuals); + ConstantArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getVariableArrayType - Returns a non-unique reference to the type for a +/// variable array of the specified element type. +QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + // Since we don't unique expressions, it isn't possible to unique VLA's + // that have an expression provided for their size. + + VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts, + ASM, EltTypeQuals); + + VariableArrayTypes.push_back(New); + Types.push_back(New); + return QualType(New, 0); +} + +QualType ASTContext::getIncompleteArrayType(QualType EltTy, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + llvm::FoldingSetNodeID ID; + IncompleteArrayType::Profile(ID, EltTy); + + void *InsertPos = 0; + if (IncompleteArrayType *ATP = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ATP, 0); + + // If the element type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + + if (!EltTy->isCanonical()) { + Canonical = getIncompleteArrayType(EltTy.getCanonicalType(), + ASM, EltTypeQuals); + + // Get the new insert position for the node we care about. + IncompleteArrayType *NewIP = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + IncompleteArrayType *New = new IncompleteArrayType(EltTy, Canonical, + ASM, EltTypeQuals); + + IncompleteArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getVectorType - Return the unique reference to a vector type of +/// the specified element type and size. VectorType must be a built-in type. +QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { + BuiltinType *baseType; + + baseType = dyn_cast(vecType.getCanonicalType().getTypePtr()); + assert(baseType != 0 && "getVectorType(): Expecting a built-in type"); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts, Type::Vector); + void *InsertPos = 0; + if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(VTP, 0); + + // If the element type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!vecType->isCanonical()) { + Canonical = getVectorType(vecType.getCanonicalType(), NumElts); + + // Get the new insert position for the node we care about. + VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + VectorType *New = new VectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getOCUVectorType - Return the unique reference to an OCU vector type of +/// the specified element type and size. VectorType must be a built-in type. +QualType ASTContext::getOCUVectorType(QualType vecType, unsigned NumElts) { + BuiltinType *baseType; + + baseType = dyn_cast(vecType.getCanonicalType().getTypePtr()); + assert(baseType != 0 && "getOCUVectorType(): Expecting a built-in type"); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts, Type::OCUVector); + void *InsertPos = 0; + if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(VTP, 0); + + // If the element type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!vecType->isCanonical()) { + Canonical = getOCUVectorType(vecType.getCanonicalType(), NumElts); + + // Get the new insert position for the node we care about. + VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + OCUVectorType *New = new OCUVectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'. +/// +QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionTypeNoProto::Profile(ID, ResultTy); + + void *InsertPos = 0; + if (FunctionTypeNoProto *FT = + FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FT, 0); + + QualType Canonical; + if (!ResultTy->isCanonical()) { + Canonical = getFunctionTypeNoProto(ResultTy.getCanonicalType()); + + // Get the new insert position for the node we care about. + FunctionTypeNoProto *NewIP = + FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + FunctionTypeNoProto *New = new FunctionTypeNoProto(ResultTy, Canonical); + Types.push_back(New); + FunctionTypeNoProtos.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getFunctionType - Return a normal function type with a typed argument +/// list. isVariadic indicates whether the argument list includes '...'. +QualType ASTContext::getFunctionType(QualType ResultTy, QualType *ArgArray, + unsigned NumArgs, bool isVariadic) { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic); + + void *InsertPos = 0; + if (FunctionTypeProto *FTP = + FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FTP, 0); + + // Determine whether the type being created is already canonical or not. + bool isCanonical = ResultTy->isCanonical(); + for (unsigned i = 0; i != NumArgs && isCanonical; ++i) + if (!ArgArray[i]->isCanonical()) + isCanonical = false; + + // If this type isn't canonical, get the canonical version of it. + QualType Canonical; + if (!isCanonical) { + llvm::SmallVector CanonicalArgs; + CanonicalArgs.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + CanonicalArgs.push_back(ArgArray[i].getCanonicalType()); + + Canonical = getFunctionType(ResultTy.getCanonicalType(), + &CanonicalArgs[0], NumArgs, + isVariadic); + + // Get the new insert position for the node we care about. + FunctionTypeProto *NewIP = + FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + // FunctionTypeProto objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + FunctionTypeProto *FTP = + (FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) + + NumArgs*sizeof(QualType)); + new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic, + Canonical); + Types.push_back(FTP); + FunctionTypeProtos.InsertNode(FTP, InsertPos); + return QualType(FTP, 0); +} + +/// getTypedefType - Return the unique reference to the type for the +/// specified typename decl. +QualType ASTContext::getTypedefType(TypedefDecl *Decl) { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + QualType Canonical = Decl->getUnderlyingType().getCanonicalType(); + Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); +} + +/// getObjCInterfaceType - Return the unique reference to the type for the +/// specified ObjC interface decl. +QualType ASTContext::getObjCInterfaceType(ObjCInterfaceDecl *Decl) { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + Decl->TypeForDecl = new ObjCInterfaceType(Type::ObjCInterface, Decl); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); +} + +/// getObjCQualifiedInterfaceType - Return a +/// ObjCQualifiedInterfaceType type for the given interface decl and +/// the conforming protocol list. +QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **Protocols, unsigned NumProtocols) { + llvm::FoldingSetNodeID ID; + ObjCQualifiedInterfaceType::Profile(ID, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjCQualifiedInterfaceType *QT = + ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + ObjCQualifiedInterfaceType *QType = + new ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols); + Types.push_back(QType); + ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +/// getObjCQualifiedIdType - Return a +/// getObjCQualifiedIdType type for the 'id' decl and +/// the conforming protocol list. +QualType ASTContext::getObjCQualifiedIdType(QualType idType, + ObjCProtocolDecl **Protocols, + unsigned NumProtocols) { + llvm::FoldingSetNodeID ID; + ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjCQualifiedIdType *QT = + ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + QualType Canonical; + if (!idType->isCanonical()) { + Canonical = getObjCQualifiedIdType(idType.getCanonicalType(), + Protocols, NumProtocols); + ObjCQualifiedIdType *NewQT = + ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewQT == 0 && "Shouldn't be in the map!"); + } + + ObjCQualifiedIdType *QType = + new ObjCQualifiedIdType(Canonical, Protocols, NumProtocols); + Types.push_back(QType); + ObjCQualifiedIdTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +/// getTypeOfExpr - Unlike many "get" functions, we can't unique +/// TypeOfExpr AST's (since expression's are never shared). For example, +/// multiple declarations that refer to "typeof(x)" all contain different +/// DeclRefExpr's. This doesn't effect the type checker, since it operates +/// on canonical type's (which are always unique). +QualType ASTContext::getTypeOfExpr(Expr *tofExpr) { + QualType Canonical = tofExpr->getType().getCanonicalType(); + TypeOfExpr *toe = new TypeOfExpr(tofExpr, Canonical); + Types.push_back(toe); + return QualType(toe, 0); +} + +/// getTypeOfType - Unlike many "get" functions, we don't unique +/// TypeOfType AST's. The only motivation to unique these nodes would be +/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be +/// an issue. This doesn't effect the type checker, since it operates +/// on canonical type's (which are always unique). +QualType ASTContext::getTypeOfType(QualType tofType) { + QualType Canonical = tofType.getCanonicalType(); + TypeOfType *tot = new TypeOfType(tofType, Canonical); + Types.push_back(tot); + return QualType(tot, 0); +} + +/// getTagDeclType - Return the unique reference to the type for the +/// specified TagDecl (struct/union/class/enum) decl. +QualType ASTContext::getTagDeclType(TagDecl *Decl) { + assert (Decl); + + // The decl stores the type cache. + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + TagType* T = new TagType(Decl, QualType()); + Types.push_back(T); + Decl->TypeForDecl = T; + + return QualType(T, 0); +} + +/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result +/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and +/// needs to agree with the definition in . +QualType ASTContext::getSizeType() const { + // On Darwin, size_t is defined as a "long unsigned int". + // FIXME: should derive from "Target". + return UnsignedLongTy; +} + +/// getWcharType - Return the unique type for "wchar_t" (C99 7.17), the +/// width of characters in wide strings, The value is target dependent and +/// needs to agree with the definition in . +QualType ASTContext::getWcharType() const { + // On Darwin, wchar_t is defined as a "int". + // FIXME: should derive from "Target". + return IntTy; +} + +/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) +/// defined in . Pointer - pointer requires this (C99 6.5.6p9). +QualType ASTContext::getPointerDiffType() const { + // On Darwin, ptrdiff_t is defined as a "int". This seems like a bug... + // FIXME: should derive from "Target". + return IntTy; +} + +/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This +/// routine will assert if passed a built-in type that isn't an integer or enum. +static int getIntegerRank(QualType t) { + if (const TagType *TT = dyn_cast(t.getCanonicalType())) { + assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum"); + return 4; + } + + const BuiltinType *BT = t.getCanonicalType()->getAsBuiltinType(); + switch (BT->getKind()) { + default: + assert(0 && "getIntegerRank(): not a built-in integer"); + case BuiltinType::Bool: + return 1; + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + return 2; + case BuiltinType::Short: + case BuiltinType::UShort: + return 3; + case BuiltinType::Int: + case BuiltinType::UInt: + return 4; + case BuiltinType::Long: + case BuiltinType::ULong: + return 5; + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + return 6; + } +} + +/// getFloatingRank - Return a relative rank for floating point types. +/// This routine will assert if passed a built-in type that isn't a float. +static int getFloatingRank(QualType T) { + T = T.getCanonicalType(); + if (const ComplexType *CT = T->getAsComplexType()) + return getFloatingRank(CT->getElementType()); + + switch (T->getAsBuiltinType()->getKind()) { + default: assert(0 && "getFloatingRank(): not a floating type"); + case BuiltinType::Float: return FloatRank; + case BuiltinType::Double: return DoubleRank; + case BuiltinType::LongDouble: return LongDoubleRank; + } +} + +/// getFloatingTypeOfSizeWithinDomain - Returns a real floating +/// point or a complex type (based on typeDomain/typeSize). +/// 'typeDomain' is a real floating point or complex type. +/// 'typeSize' is a real floating point or complex type. +QualType ASTContext::getFloatingTypeOfSizeWithinDomain( + QualType typeSize, QualType typeDomain) const { + if (typeDomain->isComplexType()) { + switch (getFloatingRank(typeSize)) { + default: assert(0 && "getFloatingRank(): illegal value for rank"); + case FloatRank: return FloatComplexTy; + case DoubleRank: return DoubleComplexTy; + case LongDoubleRank: return LongDoubleComplexTy; + } + } + if (typeDomain->isRealFloatingType()) { + switch (getFloatingRank(typeSize)) { + default: assert(0 && "getFloatingRank(): illegal value for rank"); + case FloatRank: return FloatTy; + case DoubleRank: return DoubleTy; + case LongDoubleRank: return LongDoubleTy; + } + } + assert(0 && "getFloatingTypeOfSizeWithinDomain(): illegal domain"); + //an invalid return value, but the assert + //will ensure that this code is never reached. + return VoidTy; +} + +/// compareFloatingType - Handles 3 different combos: +/// float/float, float/complex, complex/complex. +/// If lt > rt, return 1. If lt == rt, return 0. If lt < rt, return -1. +int ASTContext::compareFloatingType(QualType lt, QualType rt) { + if (getFloatingRank(lt) == getFloatingRank(rt)) + return 0; + if (getFloatingRank(lt) > getFloatingRank(rt)) + return 1; + return -1; +} + +// maxIntegerType - Returns the highest ranked integer type. Handles 3 case: +// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1. +QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) { + if (lhs == rhs) return lhs; + + bool t1Unsigned = lhs->isUnsignedIntegerType(); + bool t2Unsigned = rhs->isUnsignedIntegerType(); + + if ((t1Unsigned && t2Unsigned) || (!t1Unsigned && !t2Unsigned)) + return getIntegerRank(lhs) >= getIntegerRank(rhs) ? lhs : rhs; + + // We have two integer types with differing signs + QualType unsignedType = t1Unsigned ? lhs : rhs; + QualType signedType = t1Unsigned ? rhs : lhs; + + if (getIntegerRank(unsignedType) >= getIntegerRank(signedType)) + return unsignedType; + else { + // FIXME: Need to check if the signed type can represent all values of the + // unsigned type. If it can, then the result is the signed type. + // If it can't, then the result is the unsigned version of the signed type. + // Should probably add a helper that returns a signed integer type from + // an unsigned (and vice versa). C99 6.3.1.8. + return signedType; + } +} + +// getCFConstantStringType - Return the type used for constant CFStrings. +QualType ASTContext::getCFConstantStringType() { + if (!CFConstantStringTypeDecl) { + CFConstantStringTypeDecl = + RecordDecl::Create(*this, Decl::Struct, SourceLocation(), + &Idents.get("NSConstantString"), 0); + QualType FieldTypes[4]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); + // int flags; + FieldTypes[1] = IntTy; + // const char *str; + FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); + // long length; + FieldTypes[3] = LongTy; + // Create fields + FieldDecl *FieldDecls[4]; + + for (unsigned i = 0; i < 4; ++i) + FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]); + + CFConstantStringTypeDecl->defineBody(FieldDecls, 4); + } + + return getTagDeclType(CFConstantStringTypeDecl); +} + +// This returns true if a type has been typedefed to BOOL: +// typedef BOOL; +static bool isTypeTypedefedAsBOOL(QualType T) { + if (const TypedefType *TT = dyn_cast(T)) + return !strcmp(TT->getDecl()->getName(), "BOOL"); + + return false; +} + +/// getObjCEncodingTypeSize returns size of type for objective-c encoding +/// purpose. +int ASTContext::getObjCEncodingTypeSize(QualType type) { + uint64_t sz = getTypeSize(type); + + // Make all integer and enum types at least as large as an int + if (sz > 0 && type->isIntegralType()) + sz = std::max(sz, getTypeSize(IntTy)); + // Treat arrays as pointers, since that's how they're passed in. + else if (type->isArrayType()) + sz = getTypeSize(VoidPtrTy); + return sz / getTypeSize(CharTy); +} + +/// getObjCEncodingForMethodDecl - Return the encoded type for this method +/// declaration. +void ASTContext::getObjCEncodingForMethodDecl(ObjCMethodDecl *Decl, + std::string& S) +{ + // Encode type qualifer, 'in', 'inout', etc. for the return type. + getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S); + // Encode result type. + getObjCEncodingForType(Decl->getResultType(), S, EncodingRecordTypes); + // Compute size of all parameters. + // Start with computing size of a pointer in number of bytes. + // FIXME: There might(should) be a better way of doing this computation! + SourceLocation Loc; + int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy); + // The first two arguments (self and _cmd) are pointers; account for + // their size. + int ParmOffset = 2 * PtrSize; + int NumOfParams = Decl->getNumParams(); + for (int i = 0; i < NumOfParams; i++) { + QualType PType = Decl->getParamDecl(i)->getType(); + int sz = getObjCEncodingTypeSize (PType); + assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type"); + ParmOffset += sz; + } + S += llvm::utostr(ParmOffset); + S += "@0:"; + S += llvm::utostr(PtrSize); + + // Argument types. + ParmOffset = 2 * PtrSize; + for (int i = 0; i < NumOfParams; i++) { + QualType PType = Decl->getParamDecl(i)->getType(); + // Process argument qualifiers for user supplied arguments; such as, + // 'in', 'inout', etc. + getObjCEncodingForTypeQualifier( + Decl->getParamDecl(i)->getObjCDeclQualifier(), S); + getObjCEncodingForType(PType, S, EncodingRecordTypes); + S += llvm::utostr(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } +} + +void ASTContext::getObjCEncodingForType(QualType T, std::string& S, + llvm::SmallVector &ERType) const +{ + // FIXME: This currently doesn't encode: + // @ An object (whether statically typed or typed id) + // # A class object (Class) + // : A method selector (SEL) + // {name=type...} A structure + // (name=type...) A union + // bnum A bit field of num bits + + if (const BuiltinType *BT = T->getAsBuiltinType()) { + char encoding; + switch (BT->getKind()) { + case BuiltinType::Void: + encoding = 'v'; + break; + case BuiltinType::Bool: + encoding = 'B'; + break; + case BuiltinType::Char_U: + case BuiltinType::UChar: + encoding = 'C'; + break; + case BuiltinType::UShort: + encoding = 'S'; + break; + case BuiltinType::UInt: + encoding = 'I'; + break; + case BuiltinType::ULong: + encoding = 'L'; + break; + case BuiltinType::ULongLong: + encoding = 'Q'; + break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + encoding = 'c'; + break; + case BuiltinType::Short: + encoding = 's'; + break; + case BuiltinType::Int: + encoding = 'i'; + break; + case BuiltinType::Long: + encoding = 'l'; + break; + case BuiltinType::LongLong: + encoding = 'q'; + break; + case BuiltinType::Float: + encoding = 'f'; + break; + case BuiltinType::Double: + encoding = 'd'; + break; + case BuiltinType::LongDouble: + encoding = 'd'; + break; + default: + assert(0 && "Unhandled builtin type kind"); + } + + S += encoding; + } + else if (T->isObjCQualifiedIdType()) { + // Treat id same as 'id' for encoding purposes. + return getObjCEncodingForType(getObjCIdType(), S, ERType); + + } + else if (const PointerType *PT = T->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (isObjCIdType(PointeeTy) || PointeeTy->isObjCInterfaceType()) { + S += '@'; + return; + } else if (isObjCClassType(PointeeTy)) { + S += '#'; + return; + } else if (isObjCSelType(PointeeTy)) { + S += ':'; + return; + } + + if (PointeeTy->isCharType()) { + // char pointer types should be encoded as '*' unless it is a + // type that has been typedef'd to 'BOOL'. + if (!isTypeTypedefedAsBOOL(PointeeTy)) { + S += '*'; + return; + } + } + + S += '^'; + getObjCEncodingForType(PT->getPointeeType(), S, ERType); + } else if (const ArrayType *AT = T->getAsArrayType()) { + S += '['; + + if (const ConstantArrayType *CAT = dyn_cast(AT)) + S += llvm::utostr(CAT->getSize().getZExtValue()); + else + assert(0 && "Unhandled array type!"); + + getObjCEncodingForType(AT->getElementType(), S, ERType); + S += ']'; + } else if (T->getAsFunctionType()) { + S += '?'; + } else if (const RecordType *RTy = T->getAsRecordType()) { + RecordDecl *RDecl= RTy->getDecl(); + S += '{'; + S += RDecl->getName(); + bool found = false; + for (unsigned i = 0, e = ERType.size(); i != e; ++i) + if (ERType[i] == RTy) { + found = true; + break; + } + if (!found) { + ERType.push_back(RTy); + S += '='; + for (int i = 0; i < RDecl->getNumMembers(); i++) { + FieldDecl *field = RDecl->getMember(i); + getObjCEncodingForType(field->getType(), S, ERType); + } + assert(ERType.back() == RTy && "Record Type stack mismatch."); + ERType.pop_back(); + } + S += '}'; + } else if (T->isEnumeralType()) { + S += 'i'; + } else + assert(0 && "@encode for type not implemented!"); +} + +void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, + std::string& S) const { + if (QT & Decl::OBJC_TQ_In) + S += 'n'; + if (QT & Decl::OBJC_TQ_Inout) + S += 'N'; + if (QT & Decl::OBJC_TQ_Out) + S += 'o'; + if (QT & Decl::OBJC_TQ_Bycopy) + S += 'O'; + if (QT & Decl::OBJC_TQ_Byref) + S += 'R'; + if (QT & Decl::OBJC_TQ_Oneway) + S += 'V'; +} + +void ASTContext::setBuiltinVaListType(QualType T) +{ + assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!"); + + BuiltinVaListType = T; +} + +void ASTContext::setObjCIdType(TypedefDecl *TD) +{ + assert(ObjCIdType.isNull() && "'id' type already set!"); + + ObjCIdType = getTypedefType(TD); + + // typedef struct objc_object *id; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + assert(ptr && "'id' incorrectly typed"); + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + assert(rec && "'id' incorrectly typed"); + IdStructType = rec; +} + +void ASTContext::setObjCSelType(TypedefDecl *TD) +{ + assert(ObjCSelType.isNull() && "'SEL' type already set!"); + + ObjCSelType = getTypedefType(TD); + + // typedef struct objc_selector *SEL; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + assert(ptr && "'SEL' incorrectly typed"); + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + assert(rec && "'SEL' incorrectly typed"); + SelStructType = rec; +} + +void ASTContext::setObjCProtoType(QualType QT) +{ + assert(ObjCProtoType.isNull() && "'Protocol' type already set!"); + ObjCProtoType = QT; +} + +void ASTContext::setObjCClassType(TypedefDecl *TD) +{ + assert(ObjCClassType.isNull() && "'Class' type already set!"); + + ObjCClassType = getTypedefType(TD); + + // typedef struct objc_class *Class; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + assert(ptr && "'Class' incorrectly typed"); + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + assert(rec && "'Class' incorrectly typed"); + ClassStructType = rec; +} + +void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { + assert(ObjCConstantStringType.isNull() && + "'NSConstantString' type already set!"); + + ObjCConstantStringType = getObjCInterfaceType(Decl); +} + +bool ASTContext::builtinTypesAreCompatible(QualType lhs, QualType rhs) { + const BuiltinType *lBuiltin = lhs->getAsBuiltinType(); + const BuiltinType *rBuiltin = rhs->getAsBuiltinType(); + + return lBuiltin->getKind() == rBuiltin->getKind(); +} + +/// objcTypesAreCompatible - This routine is called when two types +/// are of different class; one is interface type or is +/// a qualified interface type and the other type is of a different class. +/// Example, II or II

. +bool ASTContext::objcTypesAreCompatible(QualType lhs, QualType rhs) { + if (lhs->isObjCInterfaceType() && isObjCIdType(rhs)) + return true; + else if (isObjCIdType(lhs) && rhs->isObjCInterfaceType()) + return true; + if (ObjCInterfaceType *lhsIT = + dyn_cast(lhs.getCanonicalType().getTypePtr())) { + ObjCQualifiedInterfaceType *rhsQI = + dyn_cast(rhs.getCanonicalType().getTypePtr()); + return rhsQI && (lhsIT->getDecl() == rhsQI->getDecl()); + } + else if (ObjCInterfaceType *rhsIT = + dyn_cast(rhs.getCanonicalType().getTypePtr())) { + ObjCQualifiedInterfaceType *lhsQI = + dyn_cast(lhs.getCanonicalType().getTypePtr()); + return lhsQI && (rhsIT->getDecl() == lhsQI->getDecl()); + } + return false; +} + +/// Check that 'lhs' and 'rhs' are compatible interface types. Both types +/// must be canonical types. +bool ASTContext::interfaceTypesAreCompatible(QualType lhs, QualType rhs) { + assert (lhs->isCanonical() && + "interfaceTypesAreCompatible strip typedefs of lhs"); + assert (rhs->isCanonical() && + "interfaceTypesAreCompatible strip typedefs of rhs"); + if (lhs == rhs) + return true; + ObjCInterfaceType *lhsIT = cast(lhs.getTypePtr()); + ObjCInterfaceType *rhsIT = cast(rhs.getTypePtr()); + ObjCInterfaceDecl *rhsIDecl = rhsIT->getDecl(); + ObjCInterfaceDecl *lhsIDecl = lhsIT->getDecl(); + // rhs is derived from lhs it is OK; else it is not OK. + while (rhsIDecl != NULL) { + if (rhsIDecl == lhsIDecl) + return true; + rhsIDecl = rhsIDecl->getSuperClass(); + } + return false; +} + +bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs, + QualType rhs) { + ObjCQualifiedInterfaceType *lhsQI = + dyn_cast(lhs.getCanonicalType().getTypePtr()); + assert(lhsQI && "QualifiedInterfaceTypesAreCompatible - bad lhs type"); + ObjCQualifiedInterfaceType *rhsQI = + dyn_cast(rhs.getCanonicalType().getTypePtr()); + assert(rhsQI && "QualifiedInterfaceTypesAreCompatible - bad rhs type"); + if (!interfaceTypesAreCompatible( + getObjCInterfaceType(lhsQI->getDecl()).getCanonicalType(), + getObjCInterfaceType(rhsQI->getDecl()).getCanonicalType())) + return false; + /* All protocols in lhs must have a presense in rhs. */ + for (unsigned i =0; i < lhsQI->getNumProtocols(); i++) { + bool match = false; + ObjCProtocolDecl *lhsProto = lhsQI->getProtocols(i); + for (unsigned j = 0; j < rhsQI->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQI->getProtocols(j); + if (lhsProto == rhsProto) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; +} + +/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the +/// inheritance hierarchy of 'rProto'. +static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) { + if (lProto == rProto) + return true; + ObjCProtocolDecl** RefPDecl = rProto->getReferencedProtocols(); + for (unsigned i = 0; i < rProto->getNumReferencedProtocols(); i++) + if (ProtocolCompatibleWithProtocol(lProto, RefPDecl[i])) + return true; + return false; +} + +/// ClassImplementsProtocol - Checks that 'lProto' protocol +/// has been implemented in IDecl class, its super class or categories (if +/// lookupCategory is true). +static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, + ObjCInterfaceDecl *IDecl, + bool lookupCategory) { + + // 1st, look up the class. + ObjCProtocolDecl **protoList = IDecl->getReferencedProtocols(); + for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) { + if (ProtocolCompatibleWithProtocol(lProto, protoList[i])) + return true; + } + + // 2nd, look up the category. + if (lookupCategory) + for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) { + protoList = CDecl->getReferencedProtocols(); + for (unsigned i = 0; i < CDecl->getNumReferencedProtocols(); i++) { + if (ProtocolCompatibleWithProtocol(lProto, protoList[i])) + return true; + } + } + + // 3rd, look up the super class(s) + if (IDecl->getSuperClass()) + return + ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory); + + return false; +} + +/// ObjCQualifiedIdTypesAreCompatible - Compares two types, at least +/// one of which is a protocol qualified 'id' type. When 'compare' +/// is true it is for comparison; when false, for assignment/initialization. +bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, + QualType rhs, + bool compare) { + // match id with an 'id' type in all cases. + if (const PointerType *PT = lhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) + return true; + + } + else if (const PointerType *PT = rhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) + return true; + + } + + ObjCQualifiedInterfaceType *lhsQI = 0; + ObjCQualifiedInterfaceType *rhsQI = 0; + ObjCInterfaceDecl *lhsID = 0; + ObjCInterfaceDecl *rhsID = 0; + ObjCQualifiedIdType *lhsQID = dyn_cast(lhs); + ObjCQualifiedIdType *rhsQID = dyn_cast(rhs); + + if (lhsQID) { + if (!rhsQID && rhs->getTypeClass() == Type::Pointer) { + QualType rtype = + cast(rhs.getCanonicalType())->getPointeeType(); + rhsQI = + dyn_cast( + rtype.getCanonicalType().getTypePtr()); + if (!rhsQI) { + ObjCInterfaceType *IT = dyn_cast( + rtype.getCanonicalType().getTypePtr()); + if (IT) + rhsID = IT->getDecl(); + } + } + if (!rhsQI && !rhsQID && !rhsID) + return false; + + unsigned numRhsProtocols = 0; + ObjCProtocolDecl **rhsProtoList = 0; + if (rhsQI) { + numRhsProtocols = rhsQI->getNumProtocols(); + rhsProtoList = rhsQI->getReferencedProtocols(); + } + else if (rhsQID) { + numRhsProtocols = rhsQID->getNumProtocols(); + rhsProtoList = rhsQID->getReferencedProtocols(); + } + + for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { + ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i); + bool match = false; + + // when comparing an id

on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (rhsID) { + if (ClassImplementsProtocol(lhsProto, rhsID, true)) + match = true; + } + else for (unsigned j = 0; j < numRhsProtocols; j++) { + ObjCProtocolDecl *rhsProto = rhsProtoList[j]; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { + match = true; + break; + } + } + if (!match) + return false; + } + } + else if (rhsQID) { + if (!lhsQID && lhs->getTypeClass() == Type::Pointer) { + QualType ltype = + cast(lhs.getCanonicalType())->getPointeeType(); + lhsQI = + dyn_cast( + ltype.getCanonicalType().getTypePtr()); + if (!lhsQI) { + ObjCInterfaceType *IT = dyn_cast( + ltype.getCanonicalType().getTypePtr()); + if (IT) + lhsID = IT->getDecl(); + } + } + if (!lhsQI && !lhsQID && !lhsID) + return false; + + unsigned numLhsProtocols = 0; + ObjCProtocolDecl **lhsProtoList = 0; + if (lhsQI) { + numLhsProtocols = lhsQI->getNumProtocols(); + lhsProtoList = lhsQI->getReferencedProtocols(); + } + else if (lhsQID) { + numLhsProtocols = lhsQID->getNumProtocols(); + lhsProtoList = lhsQID->getReferencedProtocols(); + } + bool match = false; + // for static type vs. qualified 'id' type, check that class implements + // one of 'id's protocols. + if (lhsID) { + for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); + if (ClassImplementsProtocol(rhsProto, lhsID, compare)) { + match = true; + break; + } + } + } + else for (unsigned i =0; i < numLhsProtocols; i++) { + match = false; + ObjCProtocolDecl *lhsProto = lhsProtoList[i]; + for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { + match = true; + break; + } + } + } + if (!match) + return false; + } + return true; +} + +bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) { + const VectorType *lVector = lhs->getAsVectorType(); + const VectorType *rVector = rhs->getAsVectorType(); + + if ((lVector->getElementType().getCanonicalType() == + rVector->getElementType().getCanonicalType()) && + (lVector->getNumElements() == rVector->getNumElements())) + return true; + return false; +} + +// C99 6.2.7p1: If both are complete types, then the following additional +// requirements apply...FIXME (handle compatibility across source files). +bool ASTContext::tagTypesAreCompatible(QualType lhs, QualType rhs) { + // "Class" and "id" are compatible built-in structure types. + if (isObjCIdType(lhs) && isObjCClassType(rhs) || + isObjCClassType(lhs) && isObjCIdType(rhs)) + return true; + + // Within a translation unit a tag type is + // only compatible with itself. + return lhs.getCanonicalType() == rhs.getCanonicalType(); +} + +bool ASTContext::pointerTypesAreCompatible(QualType lhs, QualType rhs) { + // C99 6.7.5.1p2: For two pointer types to be compatible, both shall be + // identically qualified and both shall be pointers to compatible types. + if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() || + lhs.getAddressSpace() != rhs.getAddressSpace()) + return false; + + QualType ltype = cast(lhs.getCanonicalType())->getPointeeType(); + QualType rtype = cast(rhs.getCanonicalType())->getPointeeType(); + + return typesAreCompatible(ltype, rtype); +} + +// C++ 5.17p6: When the left operand of an assignment operator denotes a +// reference to T, the operation assigns to the object of type T denoted by the +// reference. +bool ASTContext::referenceTypesAreCompatible(QualType lhs, QualType rhs) { + QualType ltype = lhs; + + if (lhs->isReferenceType()) + ltype = cast(lhs.getCanonicalType())->getReferenceeType(); + + QualType rtype = rhs; + + if (rhs->isReferenceType()) + rtype = cast(rhs.getCanonicalType())->getReferenceeType(); + + return typesAreCompatible(ltype, rtype); +} + +bool ASTContext::functionTypesAreCompatible(QualType lhs, QualType rhs) { + const FunctionType *lbase = cast(lhs.getCanonicalType()); + const FunctionType *rbase = cast(rhs.getCanonicalType()); + const FunctionTypeProto *lproto = dyn_cast(lbase); + const FunctionTypeProto *rproto = dyn_cast(rbase); + + // first check the return types (common between C99 and K&R). + if (!typesAreCompatible(lbase->getResultType(), rbase->getResultType())) + return false; + + if (lproto && rproto) { // two C99 style function prototypes + unsigned lproto_nargs = lproto->getNumArgs(); + unsigned rproto_nargs = rproto->getNumArgs(); + + if (lproto_nargs != rproto_nargs) + return false; + + // both prototypes have the same number of arguments. + if ((lproto->isVariadic() && !rproto->isVariadic()) || + (rproto->isVariadic() && !lproto->isVariadic())) + return false; + + // The use of ellipsis agree...now check the argument types. + for (unsigned i = 0; i < lproto_nargs; i++) + // C99 6.7.5.3p15: ...and each parameter declared with qualified type + // is taken as having the unqualified version of it's declared type. + if (!typesAreCompatible(lproto->getArgType(i).getUnqualifiedType(), + rproto->getArgType(i).getUnqualifiedType())) + return false; + return true; + } + if (!lproto && !rproto) // two K&R style function decls, nothing to do. + return true; + + // we have a mixture of K&R style with C99 prototypes + const FunctionTypeProto *proto = lproto ? lproto : rproto; + + if (proto->isVariadic()) + return false; + + // FIXME: Each parameter type T in the prototype must be compatible with the + // type resulting from applying the usual argument conversions to T. + return true; +} + +bool ASTContext::arrayTypesAreCompatible(QualType lhs, QualType rhs) { + // Compatible arrays must have compatible element types + QualType ltype = lhs->getAsArrayType()->getElementType(); + QualType rtype = rhs->getAsArrayType()->getElementType(); + + if (!typesAreCompatible(ltype, rtype)) + return false; + + // Compatible arrays must be the same size + if (const ConstantArrayType* LCAT = lhs->getAsConstantArrayType()) + if (const ConstantArrayType* RCAT = rhs->getAsConstantArrayType()) + return RCAT->getSize() == LCAT->getSize(); + + return true; +} + +/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, +/// both shall have the identically qualified version of a compatible type. +/// C99 6.2.7p1: Two types have compatible types if their types are the +/// same. See 6.7.[2,3,5] for additional rules. +bool ASTContext::typesAreCompatible(QualType lhs, QualType rhs) { + if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() || + lhs.getAddressSpace() != rhs.getAddressSpace()) + return false; + + QualType lcanon = lhs.getCanonicalType(); + QualType rcanon = rhs.getCanonicalType(); + + // If two types are identical, they are are compatible + if (lcanon == rcanon) + return true; + + // C++ [expr]: If an expression initially has the type "reference to T", the + // type is adjusted to "T" prior to any further analysis, the expression + // designates the object or function denoted by the reference, and the + // expression is an lvalue. + if (ReferenceType *RT = dyn_cast(lcanon)) + lcanon = RT->getReferenceeType(); + if (ReferenceType *RT = dyn_cast(rcanon)) + rcanon = RT->getReferenceeType(); + + Type::TypeClass LHSClass = lcanon->getTypeClass(); + Type::TypeClass RHSClass = rcanon->getTypeClass(); + + // We want to consider the two function types to be the same for these + // comparisons, just force one to the other. + if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto; + if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto; + + // Same as above for arrays + if (LHSClass == Type::VariableArray) LHSClass = Type::ConstantArray; + if (RHSClass == Type::VariableArray) RHSClass = Type::ConstantArray; + if (LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; + if (RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; + + // If the canonical type classes don't match... + if (LHSClass != RHSClass) { + // For Objective-C, it is possible for two types to be compatible + // when their classes don't match (when dealing with "id"). If either type + // is an interface, we defer to objcTypesAreCompatible(). + if (lcanon->isObjCInterfaceType() || rcanon->isObjCInterfaceType()) + return objcTypesAreCompatible(lcanon, rcanon); + + // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, + // a signed integer type, or an unsigned integer type. + if (lcanon->isEnumeralType() && rcanon->isIntegralType()) { + EnumDecl* EDecl = cast(cast(lcanon)->getDecl()); + return EDecl->getIntegerType() == rcanon; + } + if (rcanon->isEnumeralType() && lcanon->isIntegralType()) { + EnumDecl* EDecl = cast(cast(rcanon)->getDecl()); + return EDecl->getIntegerType() == lcanon; + } + + return false; + } + // The canonical type classes match. + switch (LHSClass) { + case Type::FunctionProto: assert(0 && "Canonicalized away above"); + case Type::Pointer: + return pointerTypesAreCompatible(lcanon, rcanon); + case Type::ConstantArray: + case Type::VariableArray: + case Type::IncompleteArray: + return arrayTypesAreCompatible(lcanon, rcanon); + case Type::FunctionNoProto: + return functionTypesAreCompatible(lcanon, rcanon); + case Type::Tagged: // handle structures, unions + return tagTypesAreCompatible(lcanon, rcanon); + case Type::Builtin: + return builtinTypesAreCompatible(lcanon, rcanon); + case Type::ObjCInterface: + return interfaceTypesAreCompatible(lcanon, rcanon); + case Type::Vector: + case Type::OCUVector: + return vectorTypesAreCompatible(lcanon, rcanon); + case Type::ObjCQualifiedInterface: + return QualifiedInterfaceTypesAreCompatible(lcanon, rcanon); + default: + assert(0 && "unexpected type"); + } + return true; // should never get here... +} + +/// Emit - Serialize an ASTContext object to Bitcode. +void ASTContext::Emit(llvm::Serializer& S) const { + S.EmitRef(SourceMgr); + S.EmitRef(Target); + S.EmitRef(Idents); + S.EmitRef(Selectors); + + // Emit the size of the type vector so that we can reserve that size + // when we reconstitute the ASTContext object. + S.EmitInt(Types.size()); + + for (std::vector::const_iterator I=Types.begin(), E=Types.end(); + I!=E;++I) + (*I)->Emit(S); + + // FIXME: S.EmitOwnedPtr(CFConstantStringTypeDecl); +} + +ASTContext* ASTContext::Create(llvm::Deserializer& D) { + SourceManager &SM = D.ReadRef(); + TargetInfo &t = D.ReadRef(); + IdentifierTable &idents = D.ReadRef(); + SelectorTable &sels = D.ReadRef(); + + unsigned size_reserve = D.ReadInt(); + + ASTContext* A = new ASTContext(SM,t,idents,sels,size_reserve); + + for (unsigned i = 0; i < size_reserve; ++i) + Type::Create(*A,i,D); + + // FIXME: A->CFConstantStringTypeDecl = D.ReadOwnedPtr(); + + return A; +} diff --git a/clang/lib/AST/Builtins.cpp b/clang/lib/AST/Builtins.cpp new file mode 100644 index 00000000000..e2bf5ca007b --- /dev/null +++ b/clang/lib/AST/Builtins.cpp @@ -0,0 +1,195 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements various things for builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Builtins.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", 0, 0 }, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/Builtins.def" +}; + +const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { + if (ID < Builtin::FirstTSBuiltin) + return BuiltinInfo[ID]; + assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + + +/// InitializeBuiltins - Mark the identifiers for all the builtins with their +/// appropriate builtin ID # and mark any non-portable builtin identifiers as +/// such. +void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, + const TargetInfo &Target) { + // Step #1: mark all target-independent builtins with their ID's. + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); + + // Step #2: Get target builtins. + Target.getTargetBuiltins(TSRecords, NumTSRecords); + + // Step #3: Register target-specific builtins. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); +} + +/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the +/// pointer over the consumed characters. This returns the resultant type. +static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, + bool AllowTypeModifiers = true) { + // Modifiers. + bool Long = false, LongLong = false, Signed = false, Unsigned = false; + + // Read the modifiers first. + bool Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case 'S': + assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); + assert(!Signed && "Can't use 'S' modifier multiple times!"); + Signed = true; + break; + case 'U': + assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); + assert(!Unsigned && "Can't use 'S' modifier multiple times!"); + Unsigned = true; + break; + case 'L': + assert(!LongLong && "Can't have LLL modifier"); + if (Long) + LongLong = true; + else + Long = true; + break; + } + } + + QualType Type; + + // Read the base type. + switch (*Str++) { + default: assert(0 && "Unknown builtin type letter!"); + case 'v': + assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); + Type = Context.VoidTy; + break; + case 'f': + assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); + Type = Context.FloatTy; + break; + case 'd': + assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); + if (Long) + Type = Context.LongDoubleTy; + else + Type = Context.DoubleTy; + break; + case 's': + assert(!LongLong && "Bad modifiers used with 's'!"); + if (Unsigned) + Type = Context.UnsignedShortTy; + else + Type = Context.ShortTy; + break; + case 'i': + if (LongLong) + Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; + else if (Long) + Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; + else if (Unsigned) + Type = Context.UnsignedIntTy; + else + Type = Context.IntTy; // default is signed. + break; + case 'c': + assert(!Long && !LongLong && "Bad modifiers used with 'c'!"); + if (Signed) + Type = Context.SignedCharTy; + else if (Unsigned) + Type = Context.UnsignedCharTy; + else + Type = Context.CharTy; + break; + case 'z': // size_t. + assert(!Long && !Signed && !Unsigned && "Bad modifiers for 'z'!"); + Type = Context.getSizeType(); + break; + case 'F': + Type = Context.getCFConstantStringType(); + break; + case 'a': + Type = Context.getBuiltinVaListType(); + assert(!Type.isNull() && "builtin va list type not initialized!"); + break; + case 'V': { + char *End; + + unsigned NumElements = strtoul(Str, &End, 10); + assert(End != Str && "Missing vector size"); + + Str = End; + + QualType ElementType = DecodeTypeFromStr(Str, Context, false); + Type = Context.getVectorType(ElementType, NumElements); + break; + } + } + + if (!AllowTypeModifiers) + return Type; + + Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case '*': + Type = Context.getPointerType(Type); + break; + case '&': + Type = Context.getReferenceType(Type); + break; + case 'C': + Type = Type.getQualifiedType(QualType::Const); + break; + } + } + + return Type; +} + +/// GetBuiltinType - Return the type for the specified builtin. +QualType Builtin::Context::GetBuiltinType(unsigned id, + ASTContext &Context) const { + const char *TypeStr = GetRecord(id).Type; + + llvm::SmallVector ArgTypes; + + QualType ResType = DecodeTypeFromStr(TypeStr, Context); + while (TypeStr[0] && TypeStr[0] != '.') + ArgTypes.push_back(DecodeTypeFromStr(TypeStr, Context)); + + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && + "'.' should only occur at end of builtin type list!"); + + // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". + if (ArgTypes.size() == 0 && TypeStr[0] == '.') + return Context.getFunctionTypeNoProto(ResType); + return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(), + TypeStr[0] == '.'); +} diff --git a/clang/lib/AST/CFG.cpp b/clang/lib/AST/CFG.cpp new file mode 100644 index 00000000000..e2aba6b3ff3 --- /dev/null +++ b/clang/lib/AST/CFG.cpp @@ -0,0 +1,1509 @@ +//===--- CFG.cpp - Classes for representing and building CFGs----*- 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 CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/CFG.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/Streams.h" +#include "llvm/Support/Compiler.h" +#include +#include +#include +#include +#include + +using namespace clang; + +namespace { + +// SaveAndRestore - A utility class that uses RIIA to save and restore +// the value of a variable. +template +struct VISIBILITY_HIDDEN SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } + + T& X; + T old_value; +}; + +/// CFGBuilder - This class is implements CFG construction from an AST. +/// The builder is stateful: an instance of the builder should be used to only +/// construct a single CFG. +/// +/// Example usage: +/// +/// CFGBuilder builder; +/// CFG* cfg = builder.BuildAST(stmt1); +/// +/// CFG construction is done via a recursive walk of an AST. +/// We actually parse the AST in reverse order so that the successor +/// of a basic block is constructed prior to its predecessor. This +/// allows us to nicely capture implicit fall-throughs without extra +/// basic blocks. +/// +class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor { + CFG* cfg; + CFGBlock* Block; + CFGBlock* Succ; + CFGBlock* ContinueTargetBlock; + CFGBlock* BreakTargetBlock; + CFGBlock* SwitchTerminatedBlock; + CFGBlock* DefaultCaseBlock; + + // LabelMap records the mapping from Label expressions to their blocks. + typedef llvm::DenseMap LabelMapTy; + LabelMapTy LabelMap; + + // A list of blocks that end with a "goto" that must be backpatched to + // their resolved targets upon completion of CFG construction. + typedef std::vector BackpatchBlocksTy; + BackpatchBlocksTy BackpatchBlocks; + + // A list of labels whose address has been taken (for indirect gotos). + typedef llvm::SmallPtrSet LabelSetTy; + LabelSetTy AddressTakenLabels; + +public: + explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL), + ContinueTargetBlock(NULL), BreakTargetBlock(NULL), + SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) { + // Create an empty CFG. + cfg = new CFG(); + } + + ~CFGBuilder() { delete cfg; } + + // buildCFG - Used by external clients to construct the CFG. + CFG* buildCFG(Stmt* Statement); + + // Visitors to walk an AST and construct the CFG. Called by + // buildCFG. Do not call directly! + + CFGBlock* VisitStmt(Stmt* Statement); + CFGBlock* VisitNullStmt(NullStmt* Statement); + CFGBlock* VisitCompoundStmt(CompoundStmt* C); + CFGBlock* VisitIfStmt(IfStmt* I); + CFGBlock* VisitReturnStmt(ReturnStmt* R); + CFGBlock* VisitLabelStmt(LabelStmt* L); + CFGBlock* VisitGotoStmt(GotoStmt* G); + CFGBlock* VisitForStmt(ForStmt* F); + CFGBlock* VisitWhileStmt(WhileStmt* W); + CFGBlock* VisitDoStmt(DoStmt* D); + CFGBlock* VisitContinueStmt(ContinueStmt* C); + CFGBlock* VisitBreakStmt(BreakStmt* B); + CFGBlock* VisitSwitchStmt(SwitchStmt* S); + CFGBlock* VisitCaseStmt(CaseStmt* S); + CFGBlock* VisitDefaultStmt(DefaultStmt* D); + CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I); + + // FIXME: Add support for ObjC-specific control-flow structures. + + CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + badCFG = true; + return Block; + } + + CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S) { + badCFG = true; + return Block; + } + +private: + CFGBlock* createBlock(bool add_successor = true); + CFGBlock* addStmt(Stmt* S); + CFGBlock* WalkAST(Stmt* S, bool AlwaysAddStmt); + CFGBlock* WalkAST_VisitChildren(Stmt* S); + CFGBlock* WalkAST_VisitDeclSubExprs(StmtIterator& I); + CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* S); + void FinishBlock(CFGBlock* B); + + bool badCFG; +}; + +/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can +/// represent an arbitrary statement. Examples include a single expression +/// or a function body (compound statement). The ownership of the returned +/// CFG is transferred to the caller. If CFG construction fails, this method +/// returns NULL. +CFG* CFGBuilder::buildCFG(Stmt* Statement) { + assert (cfg); + if (!Statement) return NULL; + + badCFG = false; + + // Create an empty block that will serve as the exit block for the CFG. + // Since this is the first block added to the CFG, it will be implicitly + // registered as the exit block. + Succ = createBlock(); + assert (Succ == &cfg->getExit()); + Block = NULL; // the EXIT block is empty. Create all other blocks lazily. + + // Visit the statements and create the CFG. + CFGBlock* B = Visit(Statement); + if (!B) B = Succ; + + if (B) { + // Finalize the last constructed block. This usually involves + // reversing the order of the statements in the block. + if (Block) FinishBlock(B); + + // Backpatch the gotos whose label -> block mappings we didn't know + // when we encountered them. + for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), + E = BackpatchBlocks.end(); I != E; ++I ) { + + CFGBlock* B = *I; + GotoStmt* G = cast(B->getTerminator()); + LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); + + // If there is no target for the goto, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (LI == LabelMap.end()) continue; + + B->addSuccessor(LI->second); + } + + // Add successors to the Indirect Goto Dispatch block (if we have one). + if (CFGBlock* B = cfg->getIndirectGotoBlock()) + for (LabelSetTy::iterator I = AddressTakenLabels.begin(), + E = AddressTakenLabels.end(); I != E; ++I ) { + + // Lookup the target block. + LabelMapTy::iterator LI = LabelMap.find(*I); + + // If there is no target block that contains label, then we are looking + // at an incomplete AST. Handle this by not registering a successor. + if (LI == LabelMap.end()) continue; + + B->addSuccessor(LI->second); + } + + Succ = B; + } + + // Create an empty entry block that has no predecessors. + cfg->setEntry(createBlock()); + + if (badCFG) { + delete cfg; + cfg = NULL; + return NULL; + } + + // NULL out cfg so that repeated calls to the builder will fail and that + // the ownership of the constructed CFG is passed to the caller. + CFG* t = cfg; + cfg = NULL; + return t; +} + +/// createBlock - Used to lazily create blocks that are connected +/// to the current (global) succcessor. +CFGBlock* CFGBuilder::createBlock(bool add_successor) { + CFGBlock* B = cfg->createBlock(); + if (add_successor && Succ) B->addSuccessor(Succ); + return B; +} + +/// FinishBlock - When the last statement has been added to the block, +/// we must reverse the statements because they have been inserted +/// in reverse order. +void CFGBuilder::FinishBlock(CFGBlock* B) { + assert (B); + B->reverseStmts(); +} + +/// addStmt - Used to add statements/expressions to the current CFGBlock +/// "Block". This method calls WalkAST on the passed statement to see if it +/// contains any short-circuit expressions. If so, it recursively creates +/// the necessary blocks for such expressions. It returns the "topmost" block +/// of the created blocks, or the original value of "Block" when this method +/// was called if no additional blocks are created. +CFGBlock* CFGBuilder::addStmt(Stmt* S) { + if (!Block) Block = createBlock(); + return WalkAST(S,true); +} + +/// WalkAST - Used by addStmt to walk the subtree of a statement and +/// add extra blocks for ternary operators, &&, and ||. We also +/// process "," and DeclStmts (which may contain nested control-flow). +CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) { + switch (S->getStmtClass()) { + case Stmt::ConditionalOperatorClass: { + ConditionalOperator* C = cast(S); + + // Create the confluence block that will "merge" the results + // of the ternary expression. + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(C); + FinishBlock(ConfluenceBlock); + + // 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. + // e.g: x ?: y is shorthand for: x ? x : y; + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = NULL; + if (C->getLHS()) { + LHSBlock = Visit(C->getLHS()); + FinishBlock(LHSBlock); + Block = NULL; + } + + // Create the block for the RHS expression. + Succ = ConfluenceBlock; + CFGBlock* RHSBlock = Visit(C->getRHS()); + FinishBlock(RHSBlock); + + // Create the block that will contain the condition. + Block = createBlock(false); + + if (LHSBlock) + Block->addSuccessor(LHSBlock); + else { + // If we have no LHS expression, add the ConfluenceBlock as a direct + // successor for the block containing the condition. Moreover, + // we need to reverse the order of the predecessors in the + // ConfluenceBlock because the RHSBlock will have been added to + // the succcessors already, and we want the first predecessor to the + // the block containing the expression for the case when the ternary + // expression evaluates to true. + Block->addSuccessor(ConfluenceBlock); + assert (ConfluenceBlock->pred_size() == 2); + std::reverse(ConfluenceBlock->pred_begin(), + ConfluenceBlock->pred_end()); + } + + Block->addSuccessor(RHSBlock); + + Block->setTerminator(C); + return addStmt(C->getCond()); + } + + case Stmt::ChooseExprClass: { + ChooseExpr* C = cast(S); + + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(C); + FinishBlock(ConfluenceBlock); + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = Visit(C->getLHS()); + FinishBlock(LHSBlock); + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = Visit(C->getRHS()); + FinishBlock(RHSBlock); + + Block = createBlock(false); + Block->addSuccessor(LHSBlock); + Block->addSuccessor(RHSBlock); + Block->setTerminator(C); + return addStmt(C->getCond()); + } + + case Stmt::DeclStmtClass: { + ScopedDecl* D = cast(S)->getDecl(); + Block->appendStmt(S); + + StmtIterator I(D); + return WalkAST_VisitDeclSubExprs(I); + } + + case Stmt::AddrLabelExprClass: { + AddrLabelExpr* A = cast(S); + AddressTakenLabels.insert(A->getLabel()); + + if (AlwaysAddStmt) Block->appendStmt(S); + return Block; + } + + case Stmt::StmtExprClass: + return WalkAST_VisitStmtExpr(cast(S)); + + case Stmt::UnaryOperatorClass: { + UnaryOperator* U = cast(S); + + // sizeof(expressions). For such expressions, + // the subexpression is not really evaluated, so + // we don't care about control-flow within the sizeof. + if (U->getOpcode() == UnaryOperator::SizeOf) { + Block->appendStmt(S); + return Block; + } + + break; + } + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast(S); + + if (B->isLogicalOp()) { // && or || + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(B); + FinishBlock(ConfluenceBlock); + + // create the block evaluating the LHS + CFGBlock* LHSBlock = createBlock(false); + LHSBlock->setTerminator(B); + + // create the block evaluating the RHS + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = Visit(B->getRHS()); + + // Now link the LHSBlock with RHSBlock. + if (B->getOpcode() == BinaryOperator::LOr) { + LHSBlock->addSuccessor(ConfluenceBlock); + LHSBlock->addSuccessor(RHSBlock); + } + else { + assert (B->getOpcode() == BinaryOperator::LAnd); + LHSBlock->addSuccessor(RHSBlock); + LHSBlock->addSuccessor(ConfluenceBlock); + } + + // Generate the blocks for evaluating the LHS. + Block = LHSBlock; + return addStmt(B->getLHS()); + } + else if (B->getOpcode() == BinaryOperator::Comma) { // , + Block->appendStmt(B); + addStmt(B->getRHS()); + return addStmt(B->getLHS()); + } + + break; + } + + case Stmt::ParenExprClass: + return WalkAST(cast(S)->getSubExpr(), AlwaysAddStmt); + + default: + break; + }; + + if (AlwaysAddStmt) Block->appendStmt(S); + return WalkAST_VisitChildren(S); +} + +/// WalkAST_VisitDeclSubExprs - Utility method to handle Decls contained in +/// DeclStmts. Because the initialization code (and sometimes the +/// the type declarations) for DeclStmts can contain arbitrary expressions, +/// we must linearize declarations to handle arbitrary control-flow induced by +/// those expressions. +CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExprs(StmtIterator& I) { + if (I == StmtIterator()) + return Block; + + Stmt* S = *I; + ++I; + WalkAST_VisitDeclSubExprs(I); + + // Optimization: Don't create separate block-level statements for literals. + + switch (S->getStmtClass()) { + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::StringLiteralClass: + break; + + // All other cases. + + default: + Block = addStmt(S); + } + + return Block; +} + +/// WalkAST_VisitChildren - Utility method to call WalkAST on the +/// children of a Stmt. +CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* S) { + CFGBlock* B = Block; + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; + I != E; ++I) + if (*I) B = WalkAST(*I); + + return B; +} + +/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement +/// expressions (a GCC extension). +CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* S) { + Block->appendStmt(S); + return VisitCompoundStmt(S->getSubStmt()); +} + +/// VisitStmt - Handle statements with no branching control flow. +CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) { + // We cannot assume that we are in the middle of a basic block, since + // the CFG might only be constructed for this single statement. If + // we have no current basic block, just create one lazily. + if (!Block) Block = createBlock(); + + // Simply add the statement to the current block. We actually + // insert statements in reverse order; this order is reversed later + // when processing the containing element in the AST. + addStmt(Statement); + + return Block; +} + +CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) { + return Block; +} + +CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { + + for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); + I != E; ++I ) { + Visit(*I); + } + + return Block; +} + +CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { + // We may see an if statement in the middle of a basic block, or + // it may be the first statement we are processing. In either case, + // we create a new basic block. First, we create the blocks for + // the then...else statements, and then we create the block containing + // the if statement. If we were in the middle of a block, we + // stop processing that block and reverse its statements. That block + // is then the implicit successor for the "then" and "else" clauses. + + // The block we were proccessing is now finished. Make it the + // successor block. + if (Block) { + Succ = Block; + FinishBlock(Block); + } + + // Process the false branch. NULL out Block so that the recursive + // call to Visit will create a new basic block. + // Null out Block so that all successor + CFGBlock* ElseBlock = Succ; + + if (Stmt* Else = I->getElse()) { + SaveAndRestore sv(Succ); + + // NULL out Block so that the recursive call to Visit will + // create a new basic block. + Block = NULL; + ElseBlock = Visit(Else); + + if (!ElseBlock) // Can occur when the Else body has all NullStmts. + ElseBlock = sv.get(); + else if (Block) + FinishBlock(ElseBlock); + } + + // Process the true branch. NULL out Block so that the recursive + // call to Visit will create a new basic block. + // Null out Block so that all successor + CFGBlock* ThenBlock; + { + Stmt* Then = I->getThen(); + assert (Then); + SaveAndRestore sv(Succ); + Block = NULL; + ThenBlock = Visit(Then); + + if (!ThenBlock) // Can occur when the Then body has all NullStmts. + ThenBlock = sv.get(); + else if (Block) + FinishBlock(ThenBlock); + } + + // Now create a new block containing the if statement. + Block = createBlock(false); + + // Set the terminator of the new block to the If statement. + Block->setTerminator(I); + + // Now add the successors. + Block->addSuccessor(ThenBlock); + Block->addSuccessor(ElseBlock); + + // Add the condition as the last statement in the new block. This + // may create new blocks as the condition may contain control-flow. Any + // newly created blocks will be pointed to be "Block". + return addStmt(I->getCond()->IgnoreParens()); +} + + +CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { + // If we were in the middle of a block we stop processing that block + // and reverse its statements. + // + // NOTE: If a "return" appears in the middle of a block, this means + // that the code afterwards is DEAD (unreachable). We still + // keep a basic block for that code; a simple "mark-and-sweep" + // from the entry block will be able to report such dead + // blocks. + if (Block) FinishBlock(Block); + + // Create the new block. + Block = createBlock(false); + + // The Exit block is the only successor. + Block->addSuccessor(&cfg->getExit()); + + // Add the return statement to the block. This may create new blocks + // if R contains control-flow (short-circuit operations). + return addStmt(R); +} + +CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { + // Get the block of the labeled statement. Add it to our map. + Visit(L->getSubStmt()); + CFGBlock* LabelBlock = Block; + + if (!LabelBlock) // This can happen when the body is empty, i.e. + LabelBlock=createBlock(); // scopes that only contains NullStmts. + + assert (LabelMap.find(L) == LabelMap.end() && "label already in map"); + LabelMap[ L ] = LabelBlock; + + // Labels partition blocks, so this is the end of the basic block + // we were processing (L is the block's label). Because this is + // label (and we have already processed the substatement) there is no + // extra control-flow to worry about. + LabelBlock->setLabel(L); + FinishBlock(LabelBlock); + + // We set Block to NULL to allow lazy creation of a new block + // (if necessary); + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = LabelBlock; + + return LabelBlock; +} + +CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) { + // Goto is a control-flow statement. Thus we stop processing the + // current block and create a new one. + if (Block) FinishBlock(Block); + Block = createBlock(false); + Block->setTerminator(G); + + // If we already know the mapping to the label block add the + // successor now. + LabelMapTy::iterator I = LabelMap.find(G->getLabel()); + + if (I == LabelMap.end()) + // We will need to backpatch this block later. + BackpatchBlocks.push_back(Block); + else + Block->addSuccessor(I->second); + + return Block; +} + +CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { + // "for" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + LoopSuccessor = Block; + } + else LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop + // can span multiple basic blocks. Thus we need the "Entry" and "Exit" + // blocks that evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(F); + + // Now add the actual condition to the condition block. Because the + // condition itself may contain control-flow, new blocks may be created. + if (Stmt* C = F->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + if (Block) FinishBlock(EntryConditionBlock); + } + + // The condition block is the implicit successor for the loop body as + // well as any code above the loop. + Succ = EntryConditionBlock; + + // Now create the loop body. + { + assert (F->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // Create a new block to contain the (bottom) of the loop body. + Block = NULL; + + // If we have increment code, insert it at the end of the body block. + if (Stmt* I = F->getInc()) Block = addStmt(I); + + // Now populate the body block, and in the process create new blocks + // as we walk the body of the loop. + CFGBlock* BodyBlock = Visit(F->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;" + else if (Block) + FinishBlock(BodyBlock); + + // This new body block is a successor to our "exit" condition block. + ExitConditionBlock->addSuccessor(BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + ExitConditionBlock->addSuccessor(LoopSuccessor); + + // If the loop contains initialization, create a new block for those + // statements. This block can also contain statements that precede + // the loop. + if (Stmt* I = F->getInit()) { + Block = createBlock(); + return addStmt(I); + } + else { + // There is no loop initialization. We are thus basically a while + // loop. NULL out Block to force lazy block construction. + Block = NULL; + Succ = EntryConditionBlock; + return EntryConditionBlock; + } +} + +CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { + // "while" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + LoopSuccessor = Block; + } + else LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop + // can span multiple basic blocks. Thus we need the "Entry" and "Exit" + // blocks that evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(W); + + // Now add the actual condition to the condition block. Because the + // condition itself may contain control-flow, new blocks may be created. + // Thus we update "Succ" after adding the condition. + if (Stmt* C = W->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + assert (Block == EntryConditionBlock); + if (Block) FinishBlock(EntryConditionBlock); + } + + // The condition block is the implicit successor for the loop body as + // well as any code above the loop. + Succ = EntryConditionBlock; + + // Process the loop body. + { + assert (W->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // NULL out Block to force lazy instantiation of blocks for the body. + Block = NULL; + + // Create the body. The returned block is the entry to the loop body. + CFGBlock* BodyBlock = Visit(W->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "while(...) ;" + else if (Block) + FinishBlock(BodyBlock); + + // Add the loop body entry as a successor to the condition. + ExitConditionBlock->addSuccessor(BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + ExitConditionBlock->addSuccessor(LoopSuccessor); + + // There can be no more statements in the condition block + // since we loop back to this block. NULL out Block to force + // lazy creation of another block. + Block = NULL; + + // Return the condition block, which is the dominating block for the loop. + Succ = EntryConditionBlock; + return EntryConditionBlock; +} + +CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) { + // "do...while" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + LoopSuccessor = Block; + } + else LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop + // can span multiple basic blocks. Thus we need the "Entry" and "Exit" + // blocks that evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(D); + + // Now add the actual condition to the condition block. Because the + // condition itself may contain control-flow, new blocks may be created. + if (Stmt* C = D->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + if (Block) FinishBlock(EntryConditionBlock); + } + + // The condition block is the implicit successor for the loop body. + Succ = EntryConditionBlock; + + // Process the loop body. + CFGBlock* BodyBlock = NULL; + { + assert (D->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // NULL out Block to force lazy instantiation of blocks for the body. + Block = NULL; + + // Create the body. The returned block is the entry to the loop body. + BodyBlock = Visit(D->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)" + else if (Block) + FinishBlock(BodyBlock); + + // Add the loop body entry as a successor to the condition. + ExitConditionBlock->addSuccessor(BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + ExitConditionBlock->addSuccessor(LoopSuccessor); + + // There can be no more statements in the body block(s) + // since we loop back to the body. NULL out Block to force + // lazy creation of another block. + Block = NULL; + + // Return the loop body, which is the dominating block for the loop. + Succ = BodyBlock; + return BodyBlock; +} + +CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { + // "continue" is a control-flow statement. Thus we stop processing the + // current block. + if (Block) FinishBlock(Block); + + // Now create a new block that ends with the continue statement. + Block = createBlock(false); + Block->setTerminator(C); + + // If there is no target for the continue, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (ContinueTargetBlock) Block->addSuccessor(ContinueTargetBlock); + + return Block; +} + +CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) { + // "break" is a control-flow statement. Thus we stop processing the + // current block. + if (Block) FinishBlock(Block); + + // Now create a new block that ends with the continue statement. + Block = createBlock(false); + Block->setTerminator(B); + + // If there is no target for the break, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (BreakTargetBlock) Block->addSuccessor(BreakTargetBlock); + + return Block; +} + +CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* S) { + // "switch" is a control-flow statement. Thus we stop processing the + // current block. + CFGBlock* SwitchSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + SwitchSuccessor = Block; + } + else SwitchSuccessor = Succ; + + // Save the current "switch" context. + SaveAndRestore save_switch(SwitchTerminatedBlock), + save_break(BreakTargetBlock), + save_default(DefaultCaseBlock); + + // Set the "default" case to be the block after the switch statement. + // If the switch statement contains a "default:", this value will + // be overwritten with the block for that code. + DefaultCaseBlock = SwitchSuccessor; + + // Create a new block that will contain the switch statement. + SwitchTerminatedBlock = createBlock(false); + + // Now process the switch body. The code after the switch is the implicit + // successor. + Succ = SwitchSuccessor; + BreakTargetBlock = SwitchSuccessor; + + // When visiting the body, the case statements should automatically get + // linked up to the switch. We also don't keep a pointer to the body, + // since all control-flow from the switch goes to case/default statements. + assert (S->getBody() && "switch must contain a non-NULL body"); + Block = NULL; + CFGBlock *BodyBlock = Visit(S->getBody()); + if (Block) FinishBlock(BodyBlock); + + // If we have no "default:" case, the default transition is to the + // code following the switch body. + SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock); + + // Add the terminator and condition in the switch block. + SwitchTerminatedBlock->setTerminator(S); + assert (S->getCond() && "switch condition must be non-NULL"); + Block = SwitchTerminatedBlock; + + return addStmt(S->getCond()); +} + +CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* S) { + // CaseStmts are essentially labels, so they are the + // first statement in a block. + + if (S->getSubStmt()) Visit(S->getSubStmt()); + CFGBlock* CaseBlock = Block; + if (!CaseBlock) CaseBlock = createBlock(); + + // Cases statements partition blocks, so this is the top of + // the basic block we were processing (the "case XXX:" is the label). + CaseBlock->setLabel(S); + FinishBlock(CaseBlock); + + // Add this block to the list of successors for the block with the + // switch statement. + assert (SwitchTerminatedBlock); + SwitchTerminatedBlock->addSuccessor(CaseBlock); + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = CaseBlock; + + return CaseBlock; +} + +CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* S) { + if (S->getSubStmt()) Visit(S->getSubStmt()); + DefaultCaseBlock = Block; + if (!DefaultCaseBlock) DefaultCaseBlock = createBlock(); + + // Default statements partition blocks, so this is the top of + // the basic block we were processing (the "default:" is the label). + DefaultCaseBlock->setLabel(S); + FinishBlock(DefaultCaseBlock); + + // Unlike case statements, we don't add the default block to the + // successors for the switch statement immediately. This is done + // when we finish processing the switch statement. This allows for + // the default case (including a fall-through to the code after the + // switch statement) to always be the last successor of a switch-terminated + // block. + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = DefaultCaseBlock; + + return DefaultCaseBlock; +} + +CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { + // Lazily create the indirect-goto dispatch block if there isn't one + // already. + CFGBlock* IBlock = cfg->getIndirectGotoBlock(); + + if (!IBlock) { + IBlock = createBlock(false); + cfg->setIndirectGotoBlock(IBlock); + } + + // IndirectGoto is a control-flow statement. Thus we stop processing the + // current block and create a new one. + if (Block) FinishBlock(Block); + Block = createBlock(false); + Block->setTerminator(I); + Block->addSuccessor(IBlock); + return addStmt(I->getTarget()); +} + + +} // end anonymous namespace + +/// createBlock - Constructs and adds a new CFGBlock to the CFG. The +/// block has no successors or predecessors. If this is the first block +/// created in the CFG, it is automatically set to be the Entry and Exit +/// of the CFG. +CFGBlock* CFG::createBlock() { + bool first_block = begin() == end(); + + // Create the block. + Blocks.push_front(CFGBlock(NumBlockIDs++)); + + // If this is the first block, set it as the Entry and Exit. + if (first_block) Entry = Exit = &front(); + + // Return the block. + return &front(); +} + +/// buildCFG - Constructs a CFG from an AST. Ownership of the returned +/// CFG is returned to the caller. +CFG* CFG::buildCFG(Stmt* Statement) { + CFGBuilder Builder; + return Builder.buildCFG(Statement); +} + +/// reverseStmts - Reverses the orders of statements within a CFGBlock. +void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); } + +//===----------------------------------------------------------------------===// +// CFG: Queries for BlkExprs. +//===----------------------------------------------------------------------===// + +namespace { + typedef llvm::DenseMap BlkExprMapTy; +} + +static void FindSubExprAssignments(Stmt* S, llvm::SmallPtrSet& Set) { + if (!S) + return; + + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { + if (!*I) continue; + + if (BinaryOperator* B = dyn_cast(*I)) + if (B->isAssignmentOp()) Set.insert(B); + + FindSubExprAssignments(*I, Set); + } +} + +static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { + BlkExprMapTy* M = new BlkExprMapTy(); + + // Look for assignments that are used as subexpressions. These are the + // only assignments that we want to register as a block-level expression. + llvm::SmallPtrSet SubExprAssignments; + + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) + for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) + FindSubExprAssignments(*BI, SubExprAssignments); + + // Iterate over the statements again on identify the Expr* and Stmt* at + // the block-level that are block-level expressions. + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) + for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) + if (Expr* E = dyn_cast(*BI)) { + + if (BinaryOperator* B = dyn_cast(E)) { + // Assignment expressions that are not nested within another + // expression are really "statements" whose value is never + // used by another expression. + if (B->isAssignmentOp() && !SubExprAssignments.count(E)) + continue; + } + else if (const StmtExpr* S = dyn_cast(E)) { + // Special handling for statement expressions. The last statement + // in the statement expression is also a block-level expr. + const CompoundStmt* C = S->getSubStmt(); + if (!C->body_empty()) { + unsigned x = M->size(); + (*M)[C->body_back()] = x; + } + } + + unsigned x = M->size(); + (*M)[E] = x; + } + + return M; +} + +CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { + assert(S != NULL); + if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); } + + BlkExprMapTy* M = reinterpret_cast(BlkExprMap); + BlkExprMapTy::iterator I = M->find(S); + + if (I == M->end()) return CFG::BlkExprNumTy(); + else return CFG::BlkExprNumTy(I->second); +} + +unsigned CFG::getNumBlkExprs() { + if (const BlkExprMapTy* M = reinterpret_cast(BlkExprMap)) + return M->size(); + else { + // We assume callers interested in the number of BlkExprs will want + // the map constructed if it doesn't already exist. + BlkExprMap = (void*) PopulateBlkExprMap(*this); + return reinterpret_cast(BlkExprMap)->size(); + } +} + +typedef std::set > BlkEdgeSetTy; + +const std::pair* +CFG::getBlockEdgeImpl(const CFGBlock* B1, const CFGBlock* B2) { + + BlkEdgeSetTy*& p = reinterpret_cast(BlkEdgeSet); + if (!p) p = new BlkEdgeSetTy(); + + return &*(p->insert(std::make_pair(const_cast(B1), + const_cast(B2))).first); +} + +CFG::~CFG() { + delete reinterpret_cast(BlkExprMap); + delete reinterpret_cast(BlkEdgeSet); +} + +//===----------------------------------------------------------------------===// +// CFG pretty printing +//===----------------------------------------------------------------------===// + +namespace { + +class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { + + typedef llvm::DenseMap > StmtMapTy; + StmtMapTy StmtMap; + signed CurrentBlock; + unsigned CurrentStmt; + +public: + + StmtPrinterHelper(const CFG* cfg) : CurrentBlock(0), CurrentStmt(0) { + for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { + unsigned j = 1; + for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ; + BI != BEnd; ++BI, ++j ) + StmtMap[*BI] = std::make_pair(I->getBlockID(),j); + } + } + + virtual ~StmtPrinterHelper() {} + + void setBlockID(signed i) { CurrentBlock = i; } + void setStmtID(unsigned i) { CurrentStmt = i; } + + virtual bool handledStmt(Stmt* S, std::ostream& OS) { + + StmtMapTy::iterator I = StmtMap.find(S); + + if (I == StmtMap.end()) + return false; + + if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock + && I->second.second == CurrentStmt) + return false; + + OS << "[B" << I->second.first << "." << I->second.second << "]"; + return true; + } +}; + +class VISIBILITY_HIDDEN CFGBlockTerminatorPrint + : public StmtVisitor { + + std::ostream& OS; + StmtPrinterHelper* Helper; +public: + CFGBlockTerminatorPrint(std::ostream& os, StmtPrinterHelper* helper) + : OS(os), Helper(helper) {} + + void VisitIfStmt(IfStmt* I) { + OS << "if "; + I->getCond()->printPretty(OS,Helper); + } + + // Default case. + void VisitStmt(Stmt* S) { S->printPretty(OS); } + + void VisitForStmt(ForStmt* F) { + OS << "for (" ; + if (F->getInit()) OS << "..."; + OS << "; "; + if (Stmt* C = F->getCond()) C->printPretty(OS,Helper); + OS << "; "; + if (F->getInc()) OS << "..."; + OS << ")"; + } + + void VisitWhileStmt(WhileStmt* W) { + OS << "while " ; + if (Stmt* C = W->getCond()) C->printPretty(OS,Helper); + } + + void VisitDoStmt(DoStmt* D) { + OS << "do ... while "; + if (Stmt* C = D->getCond()) C->printPretty(OS,Helper); + } + + void VisitSwitchStmt(SwitchStmt* S) { + OS << "switch "; + S->getCond()->printPretty(OS,Helper); + } + + void VisitConditionalOperator(ConditionalOperator* C) { + C->getCond()->printPretty(OS,Helper); + OS << " ? ... : ..."; + } + + void VisitChooseExpr(ChooseExpr* C) { + OS << "__builtin_choose_expr( "; + C->getCond()->printPretty(OS,Helper); + OS << " )"; + } + + void VisitIndirectGotoStmt(IndirectGotoStmt* I) { + OS << "goto *"; + I->getTarget()->printPretty(OS,Helper); + } + + void VisitBinaryOperator(BinaryOperator* B) { + if (!B->isLogicalOp()) { + VisitExpr(B); + return; + } + + B->getLHS()->printPretty(OS,Helper); + + switch (B->getOpcode()) { + case BinaryOperator::LOr: + OS << " || ..."; + return; + case BinaryOperator::LAnd: + OS << " && ..."; + return; + default: + assert(false && "Invalid logical operator."); + } + } + + void VisitExpr(Expr* E) { + E->printPretty(OS,Helper); + } +}; + + +void print_stmt(std::ostream&OS, StmtPrinterHelper* Helper, Stmt* S) { + if (Helper) { + // special printing for statement-expressions. + if (StmtExpr* SE = dyn_cast(S)) { + CompoundStmt* Sub = SE->getSubStmt(); + + if (Sub->child_begin() != Sub->child_end()) { + OS << "({ ... ; "; + Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS); + OS << " })\n"; + return; + } + } + + // special printing for comma expressions. + if (BinaryOperator* B = dyn_cast(S)) { + if (B->getOpcode() == BinaryOperator::Comma) { + OS << "... , "; + Helper->handledStmt(B->getRHS(),OS); + OS << '\n'; + return; + } + } + } + + S->printPretty(OS, Helper); + + // Expressions need a newline. + if (isa(S)) OS << '\n'; +} + +void print_block(std::ostream& OS, const CFG* cfg, const CFGBlock& B, + StmtPrinterHelper* Helper, bool print_edges) { + + if (Helper) Helper->setBlockID(B.getBlockID()); + + // Print the header. + OS << "\n [ B" << B.getBlockID(); + + if (&B == &cfg->getEntry()) + OS << " (ENTRY) ]\n"; + else if (&B == &cfg->getExit()) + OS << " (EXIT) ]\n"; + else if (&B == cfg->getIndirectGotoBlock()) + OS << " (INDIRECT GOTO DISPATCH) ]\n"; + else + OS << " ]\n"; + + // Print the label of this block. + if (Stmt* S = const_cast(B.getLabel())) { + + if (print_edges) + OS << " "; + + if (LabelStmt* L = dyn_cast(S)) + OS << L->getName(); + else if (CaseStmt* C = dyn_cast(S)) { + OS << "case "; + C->getLHS()->printPretty(OS); + if (C->getRHS()) { + OS << " ... "; + C->getRHS()->printPretty(OS); + } + } + else if (isa(S)) + OS << "default"; + else + assert(false && "Invalid label statement in CFGBlock."); + + OS << ":\n"; + } + + // Iterate through the statements in the block and print them. + unsigned j = 1; + + for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; + I != E ; ++I, ++j ) { + + // Print the statement # in the basic block and the statement itself. + if (print_edges) + OS << " "; + + OS << std::setw(3) << j << ": "; + + if (Helper) + Helper->setStmtID(j); + + print_stmt(OS,Helper,*I); + } + + // Print the terminator of this block. + if (B.getTerminator()) { + if (print_edges) + OS << " "; + + OS << " T: "; + + if (Helper) Helper->setBlockID(-1); + + CFGBlockTerminatorPrint TPrinter(OS,Helper); + TPrinter.Visit(const_cast(B.getTerminator())); + OS << '\n'; + } + + if (print_edges) { + // Print the predecessors of this block. + OS << " Predecessors (" << B.pred_size() << "):"; + unsigned i = 0; + + for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) == 0) + OS << "\n "; + + OS << " B" << (*I)->getBlockID(); + } + + OS << '\n'; + + // Print the successors of this block. + OS << " Successors (" << B.succ_size() << "):"; + i = 0; + + for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) % 10 == 0) + OS << "\n "; + + OS << " B" << (*I)->getBlockID(); + } + + OS << '\n'; + } +} + +} // end anonymous namespace + +/// dump - A simple pretty printer of a CFG that outputs to stderr. +void CFG::dump() const { print(*llvm::cerr.stream()); } + +/// print - A simple pretty printer of a CFG that outputs to an ostream. +void CFG::print(std::ostream& OS) const { + + StmtPrinterHelper Helper(this); + + // Print the entry block. + print_block(OS, this, getEntry(), &Helper, true); + + // Iterate through the CFGBlocks and print them one by one. + for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { + // Skip the entry block, because we already printed it. + if (&(*I) == &getEntry() || &(*I) == &getExit()) + continue; + + print_block(OS, this, *I, &Helper, true); + } + + // Print the exit block. + print_block(OS, this, getExit(), &Helper, true); +} + +/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. +void CFGBlock::dump(const CFG* cfg) const { print(*llvm::cerr.stream(), cfg); } + +/// print - A simple pretty printer of a CFGBlock that outputs to an ostream. +/// Generally this will only be called from CFG::print. +void CFGBlock::print(std::ostream& OS, const CFG* cfg) const { + StmtPrinterHelper Helper(cfg); + print_block(OS, cfg, *this, &Helper, true); +} + +/// printTerminator - A simple pretty printer of the terminator of a CFGBlock. +void CFGBlock::printTerminator(std::ostream& OS) const { + CFGBlockTerminatorPrint TPrinter(OS,NULL); + TPrinter.Visit(const_cast(getTerminator())); +} + + +//===----------------------------------------------------------------------===// +// CFG Graphviz Visualization +//===----------------------------------------------------------------------===// + + +#ifndef NDEBUG +static StmtPrinterHelper* GraphHelper; +#endif + +void CFG::viewCFG() const { +#ifndef NDEBUG + StmtPrinterHelper H(this); + GraphHelper = &H; + llvm::ViewGraph(this,"CFG"); + GraphHelper = NULL; +#else + std::cerr << "CFG::viewCFG is only available in debug builds on " + << "systems with Graphviz or gv!\n"; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits : public DefaultDOTGraphTraits { + static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { + +#ifndef NDEBUG + std::ostringstream Out; + print_block(Out,Graph, *Node, GraphHelper, false); + std::string OutStr = Out.str(); + + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } + + return OutStr; +#else + return ""; +#endif + } +}; +} // end namespace llvm diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp new file mode 100644 index 00000000000..7fa679cbc08 --- /dev/null +++ b/clang/lib/AST/Decl.cpp @@ -0,0 +1,652 @@ +//===--- Decl.cpp - Declaration AST Node Implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Decl class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/DenseMap.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Statistics +//===----------------------------------------------------------------------===// + +// temporary statistics gathering +static unsigned nFuncs = 0; +static unsigned nBlockVars = 0; +static unsigned nFileVars = 0; +static unsigned nParmVars = 0; +static unsigned nSUC = 0; +static unsigned nEnumConst = 0; +static unsigned nEnumDecls = 0; +static unsigned nTypedef = 0; +static unsigned nFieldDecls = 0; +static unsigned nInterfaceDecls = 0; +static unsigned nClassDecls = 0; +static unsigned nMethodDecls = 0; +static unsigned nProtocolDecls = 0; +static unsigned nForwardProtocolDecls = 0; +static unsigned nCategoryDecls = 0; +static unsigned nIvarDecls = 0; +static unsigned nObjCImplementationDecls = 0; +static unsigned nObjCCategoryImpl = 0; +static unsigned nObjCCompatibleAlias = 0; +static unsigned nObjCPropertyDecl = 0; +static unsigned nLinkageSpecDecl = 0; +static unsigned nFileScopeAsmDecl = 0; + +static bool StatSwitch = false; + +// This keeps track of all decl attributes. Since so few decls have attrs, we +// keep them in a hash map instead of wasting space in the Decl class. +typedef llvm::DenseMap DeclAttrMapTy; + +static DeclAttrMapTy *DeclAttrs = 0; + +const char *Decl::getDeclKindName() const { + switch (DeclKind) { + default: assert(0 && "Unknown decl kind!"); + case Typedef: return "Typedef"; + case Function: return "Function"; + case BlockVar: return "BlockVar"; + case FileVar: return "FileVar"; + case ParmVar: return "ParmVar"; + case EnumConstant: return "EnumConstant"; + case ObjCInterface: return "ObjCInterface"; + case ObjCClass: return "ObjCClass"; + case ObjCMethod: return "ObjCMethod"; + case ObjCProtocol: return "ObjCProtocol"; + case ObjCForwardProtocol: return "ObjCForwardProtocol"; + case Struct: return "Struct"; + case Union: return "Union"; + case Class: return "Class"; + case Enum: return "Enum"; + } +} + +bool Decl::CollectingStats(bool Enable) { + if (Enable) + StatSwitch = true; + return StatSwitch; +} + +void Decl::PrintStats() { + fprintf(stderr, "*** Decl Stats:\n"); + fprintf(stderr, " %d decls total.\n", + int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+ + nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+ + nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls)); + fprintf(stderr, " %d function decls, %d each (%d bytes)\n", + nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl))); + fprintf(stderr, " %d block variable decls, %d each (%d bytes)\n", + nBlockVars, (int)sizeof(BlockVarDecl), + int(nBlockVars*sizeof(BlockVarDecl))); + fprintf(stderr, " %d file variable decls, %d each (%d bytes)\n", + nFileVars, (int)sizeof(FileVarDecl), + int(nFileVars*sizeof(FileVarDecl))); + fprintf(stderr, " %d parameter variable decls, %d each (%d bytes)\n", + nParmVars, (int)sizeof(ParmVarDecl), + int(nParmVars*sizeof(ParmVarDecl))); + fprintf(stderr, " %d field decls, %d each (%d bytes)\n", + nFieldDecls, (int)sizeof(FieldDecl), + int(nFieldDecls*sizeof(FieldDecl))); + fprintf(stderr, " %d struct/union/class decls, %d each (%d bytes)\n", + nSUC, (int)sizeof(RecordDecl), + int(nSUC*sizeof(RecordDecl))); + fprintf(stderr, " %d enum decls, %d each (%d bytes)\n", + nEnumDecls, (int)sizeof(EnumDecl), + int(nEnumDecls*sizeof(EnumDecl))); + fprintf(stderr, " %d enum constant decls, %d each (%d bytes)\n", + nEnumConst, (int)sizeof(EnumConstantDecl), + int(nEnumConst*sizeof(EnumConstantDecl))); + fprintf(stderr, " %d typedef decls, %d each (%d bytes)\n", + nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl))); + // Objective-C decls... + fprintf(stderr, " %d interface decls, %d each (%d bytes)\n", + nInterfaceDecls, (int)sizeof(ObjCInterfaceDecl), + int(nInterfaceDecls*sizeof(ObjCInterfaceDecl))); + fprintf(stderr, " %d instance variable decls, %d each (%d bytes)\n", + nIvarDecls, (int)sizeof(ObjCIvarDecl), + int(nIvarDecls*sizeof(ObjCIvarDecl))); + fprintf(stderr, " %d class decls, %d each (%d bytes)\n", + nClassDecls, (int)sizeof(ObjCClassDecl), + int(nClassDecls*sizeof(ObjCClassDecl))); + fprintf(stderr, " %d method decls, %d each (%d bytes)\n", + nMethodDecls, (int)sizeof(ObjCMethodDecl), + int(nMethodDecls*sizeof(ObjCMethodDecl))); + fprintf(stderr, " %d protocol decls, %d each (%d bytes)\n", + nProtocolDecls, (int)sizeof(ObjCProtocolDecl), + int(nProtocolDecls*sizeof(ObjCProtocolDecl))); + fprintf(stderr, " %d forward protocol decls, %d each (%d bytes)\n", + nForwardProtocolDecls, (int)sizeof(ObjCForwardProtocolDecl), + int(nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl))); + fprintf(stderr, " %d category decls, %d each (%d bytes)\n", + nCategoryDecls, (int)sizeof(ObjCCategoryDecl), + int(nCategoryDecls*sizeof(ObjCCategoryDecl))); + + fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n", + nObjCImplementationDecls, (int)sizeof(ObjCImplementationDecl), + int(nObjCImplementationDecls*sizeof(ObjCImplementationDecl))); + + fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n", + nObjCCategoryImpl, (int)sizeof(ObjCCategoryImplDecl), + int(nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl))); + + fprintf(stderr, " %d compatibility alias decls, %d each (%d bytes)\n", + nObjCCompatibleAlias, (int)sizeof(ObjCCompatibleAliasDecl), + int(nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl))); + + fprintf(stderr, " %d property decls, %d each (%d bytes)\n", + nObjCPropertyDecl, (int)sizeof(ObjCPropertyDecl), + int(nObjCPropertyDecl*sizeof(ObjCPropertyDecl))); + + fprintf(stderr, "Total bytes = %d\n", + int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+ + nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ + nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ + nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ + nTypedef*sizeof(TypedefDecl)+ + nInterfaceDecls*sizeof(ObjCInterfaceDecl)+ + nIvarDecls*sizeof(ObjCIvarDecl)+ + nClassDecls*sizeof(ObjCClassDecl)+ + nMethodDecls*sizeof(ObjCMethodDecl)+ + nProtocolDecls*sizeof(ObjCProtocolDecl)+ + nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl)+ + nCategoryDecls*sizeof(ObjCCategoryDecl)+ + nObjCImplementationDecls*sizeof(ObjCImplementationDecl)+ + nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl)+ + nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl)+ + nObjCPropertyDecl*sizeof(ObjCPropertyDecl)+ + nLinkageSpecDecl*sizeof(LinkageSpecDecl)+ + nFileScopeAsmDecl*sizeof(FileScopeAsmDecl))); + +} + +void Decl::addDeclKind(Kind k) { + switch (k) { + case Typedef: nTypedef++; break; + case Function: nFuncs++; break; + case BlockVar: nBlockVars++; break; + case FileVar: nFileVars++; break; + case ParmVar: nParmVars++; break; + case EnumConstant: nEnumConst++; break; + case Field: nFieldDecls++; break; + case Struct: case Union: case Class: nSUC++; break; + case Enum: nEnumDecls++; break; + case ObjCInterface: nInterfaceDecls++; break; + case ObjCClass: nClassDecls++; break; + case ObjCMethod: nMethodDecls++; break; + case ObjCProtocol: nProtocolDecls++; break; + case ObjCForwardProtocol: nForwardProtocolDecls++; break; + case ObjCCategory: nCategoryDecls++; break; + case ObjCIvar: nIvarDecls++; break; + case ObjCImplementation: nObjCImplementationDecls++; break; + case ObjCCategoryImpl: nObjCCategoryImpl++; break; + case CompatibleAlias: nObjCCompatibleAlias++; break; + case PropertyDecl: nObjCPropertyDecl++; break; + case LinkageSpec: nLinkageSpecDecl++; break; + case FileScopeAsm: nFileScopeAsmDecl++; break; + } +} + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +BlockVarDecl *BlockVarDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + StorageClass S, ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) BlockVarDecl(L, Id, T, S, PrevDecl); +} + + +FileVarDecl *FileVarDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) FileVarDecl(L, Id, T, S, PrevDecl); +} + +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) ParmVarDecl(L, Id, T, S, PrevDecl); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + StorageClass S, bool isInline, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) FunctionDecl(L, Id, T, S, isInline, PrevDecl); +} + + +EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *E, const llvm::APSInt &V, + ScopedDecl *PrevDecl){ + void *Mem = C.getAllocator().Allocate(); + return new (Mem) EnumConstantDecl(L, Id, T, E, V, PrevDecl); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + ScopedDecl *PD) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) TypedefDecl(L, Id, T, PD); +} + +EnumDecl *EnumDecl::Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) EnumDecl(L, Id, PrevDecl); +} + +RecordDecl *RecordDecl::Create(ASTContext &C, Kind DK, SourceLocation L, + IdentifierInfo *Id, ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate(); + return new (Mem) RecordDecl(DK, L, Id, PrevDecl); +} + + +//===----------------------------------------------------------------------===// +// Decl Implementation +//===----------------------------------------------------------------------===// + +// Out-of-line virtual method providing a home for Decl. +Decl::~Decl() { + if (!HasAttrs) + return; + + DeclAttrMapTy::iterator it = DeclAttrs->find(this); + assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!"); + + delete it->second; + DeclAttrs->erase(it); + if (DeclAttrs->empty()) { + delete DeclAttrs; + DeclAttrs = 0; + } +} + +void Decl::addAttr(Attr *NewAttr) { + if (!DeclAttrs) + DeclAttrs = new llvm::DenseMap(); + + Attr *&ExistingAttr = (*DeclAttrs)[this]; + + NewAttr->setNext(ExistingAttr); + ExistingAttr = NewAttr; + + HasAttrs = true; +} + +const Attr *Decl::getAttrs() const { + if (!HasAttrs) + return 0; + + return (*DeclAttrs)[this]; +} + +const char *NamedDecl::getName() const { + if (const IdentifierInfo *II = getIdentifier()) + return II->getName(); + return ""; +} + +FunctionDecl::~FunctionDecl() { + delete[] ParamInfo; +} + +unsigned FunctionDecl::getNumParams() const { + if (isa(getCanonicalType())) + return 0; + return cast(getCanonicalType())->getNumArgs(); +} + +void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + assert(NumParams == getNumParams() && "Parameter count mismatch!"); + + // Zero params -> null pointer. + if (NumParams) { + ParamInfo = new ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + + +/// defineBody - When created, RecordDecl's correspond to a forward declared +/// record. This method is used to mark the decl as being defined, with the +/// specified contents. +void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) { + assert(!isDefinition() && "Cannot redefine record!"); + setDefinition(true); + NumMembers = numMembers; + if (numMembers) { + Members = new FieldDecl*[numMembers]; + memcpy(Members, members, numMembers*sizeof(Decl*)); + } +} + +FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { + if (Members == 0 || NumMembers < 0) + return 0; + + // linear search. When C++ classes come along, will likely need to revisit. + for (int i = 0; i < NumMembers; ++i) { + if (Members[i]->getIdentifier() == name) + return Members[i]; + } + return 0; +} + +//===----------------------------------------------------------------------===// +// Objective-C Decl Implementation +//===----------------------------------------------------------------------===// + +void ObjCMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo, + unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + + // Zero params -> null pointer. + if (NumParams) { + ParamInfo = new ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + NumMethodParams = NumParams; + } +} + +ObjCMethodDecl::~ObjCMethodDecl() { + delete[] ParamInfo; +} + +/// ObjCAddInstanceVariablesToClass - Inserts instance variables +/// into ObjCInterfaceDecl's fields. +/// +void ObjCInterfaceDecl::addInstanceVariablesToClass(ObjCIvarDecl **ivars, + unsigned numIvars, + SourceLocation RBrac) { + NumIvars = numIvars; + if (numIvars) { + Ivars = new ObjCIvarDecl*[numIvars]; + memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); + } + setLocEnd(RBrac); +} + +/// ObjCAddInstanceVariablesToClassImpl - Checks for correctness of Instance +/// Variables (Ivars) relative to what declared in @implementation;s class. +/// Ivars into ObjCImplementationDecl's fields. +/// +void ObjCImplementationDecl::ObjCAddInstanceVariablesToClassImpl( + ObjCIvarDecl **ivars, unsigned numIvars) { + NumIvars = numIvars; + if (numIvars) { + Ivars = new ObjCIvarDecl*[numIvars]; + memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); + } +} + +/// addMethods - Insert instance and methods declarations into +/// ObjCInterfaceDecl's InsMethods and ClsMethods fields. +/// +void ObjCInterfaceDecl::addMethods(ObjCMethodDecl **insMethods, + unsigned numInsMembers, + ObjCMethodDecl **clsMethods, + unsigned numClsMembers, + SourceLocation endLoc) { + NumInstanceMethods = numInsMembers; + if (numInsMembers) { + InstanceMethods = new ObjCMethodDecl*[numInsMembers]; + memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); + } + NumClassMethods = numClsMembers; + if (numClsMembers) { + ClassMethods = new ObjCMethodDecl*[numClsMembers]; + memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); + } + AtEndLoc = endLoc; +} + +/// addMethods - Insert instance and methods declarations into +/// ObjCProtocolDecl's ProtoInsMethods and ProtoClsMethods fields. +/// +void ObjCProtocolDecl::addMethods(ObjCMethodDecl **insMethods, + unsigned numInsMembers, + ObjCMethodDecl **clsMethods, + unsigned numClsMembers, + SourceLocation endLoc) { + NumInstanceMethods = numInsMembers; + if (numInsMembers) { + InstanceMethods = new ObjCMethodDecl*[numInsMembers]; + memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); + } + NumClassMethods = numClsMembers; + if (numClsMembers) { + ClassMethods = new ObjCMethodDecl*[numClsMembers]; + memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); + } + AtEndLoc = endLoc; +} + +/// addMethods - Insert instance and methods declarations into +/// ObjCCategoryDecl's CatInsMethods and CatClsMethods fields. +/// +void ObjCCategoryDecl::addMethods(ObjCMethodDecl **insMethods, + unsigned numInsMembers, + ObjCMethodDecl **clsMethods, + unsigned numClsMembers, + SourceLocation endLoc) { + NumInstanceMethods = numInsMembers; + if (numInsMembers) { + InstanceMethods = new ObjCMethodDecl*[numInsMembers]; + memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); + } + NumClassMethods = numClsMembers; + if (numClsMembers) { + ClassMethods = new ObjCMethodDecl*[numClsMembers]; + memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); + } + AtEndLoc = endLoc; +} + +ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( + IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { + ObjCInterfaceDecl* ClassDecl = this; + while (ClassDecl != NULL) { + for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end(); + I != E; ++I) { + if ((*I)->getIdentifier() == ID) { + clsDeclared = ClassDecl; + return *I; + } + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +/// lookupInstanceMethod - This method returns an instance method by looking in +/// the class, its categories, and its super classes (using a linear search). +ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) { + ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getInstanceMethod(Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); + int numProtocols = ClassDecl->getNumIntfRefProtocols(); + for (int pIdx = 0; pIdx < numProtocols; pIdx++) { + if ((MethodDecl = protocols[pIdx]->getInstanceMethod(Sel))) + return MethodDecl; + } + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getInstanceMethod(Sel))) + return MethodDecl; + CatDecl = CatDecl->getNextClassCategory(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +// lookupClassMethod - This method returns a class method by looking in the +// class, its categories, and its super classes (using a linear search). +ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { + ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getClassMethod(Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); + int numProtocols = ClassDecl->getNumIntfRefProtocols(); + for (int pIdx = 0; pIdx < numProtocols; pIdx++) { + if ((MethodDecl = protocols[pIdx]->getClassMethod(Sel))) + return MethodDecl; + } + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getClassMethod(Sel))) + return MethodDecl; + CatDecl = CatDecl->getNextClassCategory(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +/// lookupInstanceMethod - This method returns an instance method by looking in +/// the class implementation. Unlike interfaces, we don't look outside the +/// implementation. +ObjCMethodDecl *ObjCImplementationDecl::getInstanceMethod(Selector Sel) { + for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +/// lookupClassMethod - This method returns a class method by looking in +/// the class implementation. Unlike interfaces, we don't look outside the +/// implementation. +ObjCMethodDecl *ObjCImplementationDecl::getClassMethod(Selector Sel) { + for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); + I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +// lookupInstanceMethod - This method returns an instance method by looking in +// the class implementation. Unlike interfaces, we don't look outside the +// implementation. +ObjCMethodDecl *ObjCCategoryImplDecl::getInstanceMethod(Selector Sel) { + for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +// lookupClassMethod - This method returns an instance method by looking in +// the class implementation. Unlike interfaces, we don't look outside the +// implementation. +ObjCMethodDecl *ObjCCategoryImplDecl::getClassMethod(Selector Sel) { + for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); + I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +// lookupInstanceMethod - Lookup a instance method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getInstanceMethod(Sel))) + return MethodDecl; + + if (getNumReferencedProtocols() > 0) { + ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); + + for (unsigned i = 0; i < getNumReferencedProtocols(); i++) { + if ((MethodDecl = RefPDecl[i]->getInstanceMethod(Sel))) + return MethodDecl; + } + } + return NULL; +} + +// lookupInstanceMethod - Lookup a class method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getClassMethod(Sel))) + return MethodDecl; + + if (getNumReferencedProtocols() > 0) { + ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); + + for(unsigned i = 0; i < getNumReferencedProtocols(); i++) { + if ((MethodDecl = RefPDecl[i]->getClassMethod(Sel))) + return MethodDecl; + } + } + return NULL; +} + +/// getSynthesizedMethodSize - Compute size of synthesized method name +/// as done be the rewrite. +/// +unsigned ObjCMethodDecl::getSynthesizedMethodSize() const { + // syntesized method name is a concatenation of -/+[class-name selector] + // Get length of this name. + unsigned length = 3; // _I_ or _C_ + length += strlen(getClassInterface()->getName()) +1; // extra for _ + NamedDecl *MethodContext = getMethodContext(); + if (ObjCCategoryImplDecl *CID = + dyn_cast(MethodContext)) + length += strlen(CID->getName()) +1; + length += getSelector().getName().size(); // selector name + return length; +} + +ObjCInterfaceDecl *const ObjCMethodDecl::getClassInterface() const { + if (ObjCInterfaceDecl *ID = dyn_cast(MethodContext)) + return ID; + if (ObjCCategoryDecl *CD = dyn_cast(MethodContext)) + return CD->getClassInterface(); + if (ObjCImplementationDecl *IMD = + dyn_cast(MethodContext)) + return IMD->getClassInterface(); + if (ObjCCategoryImplDecl *CID = + dyn_cast(MethodContext)) + return CID->getClassInterface(); + assert(false && "unknown method context"); + return 0; +} diff --git a/clang/lib/AST/DeclSerialization.cpp b/clang/lib/AST/DeclSerialization.cpp new file mode 100644 index 00000000000..a7eaed5b2ef --- /dev/null +++ b/clang/lib/AST/DeclSerialization.cpp @@ -0,0 +1,463 @@ +//===--- DeclSerialization.cpp - Serialization of Decls ---------*- 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 methods that implement bitcode serialization for Decls. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using llvm::Serializer; +using llvm::Deserializer; +using llvm::SerializedPtrID; + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Decl Serialization: Dispatch code to handle specialized decl types. +//===----------------------------------------------------------------------===// + +void Decl::Emit(Serializer& S) const { + S.EmitInt(getKind()); + EmitImpl(S); +} + +Decl* Decl::Create(Deserializer& D) { + + Kind k = static_cast(D.ReadInt()); + + switch (k) { + default: + assert (false && "Not implemented."); + break; + + case BlockVar: + return BlockVarDecl::CreateImpl(D); + + case Enum: + return EnumDecl::CreateImpl(D); + + case EnumConstant: + return EnumConstantDecl::CreateImpl(D); + + case Field: + return FieldDecl::CreateImpl(D); + + case FileVar: + return FileVarDecl::CreateImpl(D); + + case ParmVar: + return ParmVarDecl::CreateImpl(D); + + case Function: + return FunctionDecl::CreateImpl(D); + + case Union: + case Struct: + return RecordDecl::CreateImpl(k,D); + + case Typedef: + return TypedefDecl::CreateImpl(D); + + case FileScopeAsm: + return FileScopeAsmDecl::CreateImpl(D); + } +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of Decl. +//===----------------------------------------------------------------------===// + +void Decl::EmitInRec(Serializer& S) const { + S.Emit(getLocation()); // From Decl. +} + +void Decl::ReadInRec(Deserializer& D) { + Loc = SourceLocation::ReadVal(D); // From Decl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of NamedDecl. +//===----------------------------------------------------------------------===// + +void NamedDecl::EmitInRec(Serializer& S) const { + Decl::EmitInRec(S); + S.EmitPtr(getIdentifier()); // From NamedDecl. +} + +void NamedDecl::ReadInRec(Deserializer& D) { + Decl::ReadInRec(D); + D.ReadPtr(Identifier); // From NamedDecl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of ScopedDecl. +//===----------------------------------------------------------------------===// + +void ScopedDecl::EmitInRec(Serializer& S) const { + NamedDecl::EmitInRec(S); + S.EmitPtr(getNext()); // From ScopedDecl. +} + +void ScopedDecl::ReadInRec(Deserializer& D) { + NamedDecl::ReadInRec(D); + D.ReadPtr(Next); // From ScopedDecl. +} + + //===------------------------------------------------------------===// + // NOTE: Not all subclasses of ScopedDecl will use the "OutRec" // + // methods. This is because owned pointers are usually "batched" // + // together for efficiency. // + //===------------------------------------------------------------===// + +void ScopedDecl::EmitOutRec(Serializer& S) const { + S.EmitOwnedPtr(getNextDeclarator()); // From ScopedDecl. +} + +void ScopedDecl::ReadOutRec(Deserializer& D) { + NextDeclarator = + cast_or_null(D.ReadOwnedPtr()); // From ScopedDecl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of ValueDecl. +//===----------------------------------------------------------------------===// + +void ValueDecl::EmitInRec(Serializer& S) const { + ScopedDecl::EmitInRec(S); + S.Emit(getType()); // From ValueDecl. +} + +void ValueDecl::ReadInRec(Deserializer& D) { + ScopedDecl::ReadInRec(D); + DeclType = QualType::ReadVal(D); // From ValueDecl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of VarDecl. +//===----------------------------------------------------------------------===// + +void VarDecl::EmitInRec(Serializer& S) const { + ValueDecl::EmitInRec(S); + S.EmitInt(getStorageClass()); // From VarDecl. +} + +void VarDecl::ReadInRec(Deserializer& D) { + ValueDecl::ReadInRec(D); + SClass = static_cast(D.ReadInt()); // From VarDecl. +} + + //===------------------------------------------------------------===// + // NOTE: VarDecl has its own "OutRec" methods that doesn't use // + // the one define in ScopedDecl. This is to batch emit the // + // owned pointers, which results in a smaller output. + //===------------------------------------------------------------===// + +void VarDecl::EmitOutRec(Serializer& S) const { + // Emit these last because they will create records of their own. + S.BatchEmitOwnedPtrs(getInit(), // From VarDecl. + getNextDeclarator()); // From ScopedDecl. +} + +void VarDecl::ReadOutRec(Deserializer& D) { + Decl* next_declarator; + + D.BatchReadOwnedPtrs(Init, // From VarDecl. + next_declarator); // From ScopedDecl. + + setNextDeclarator(cast_or_null(next_declarator)); +} + + +void VarDecl::EmitImpl(Serializer& S) const { + VarDecl::EmitInRec(S); + VarDecl::EmitOutRec(S); +} + +void VarDecl::ReadImpl(Deserializer& D) { + ReadInRec(D); + ReadOutRec(D); +} + +//===----------------------------------------------------------------------===// +// BlockVarDecl Serialization. +//===----------------------------------------------------------------------===// + +BlockVarDecl* BlockVarDecl::CreateImpl(Deserializer& D) { + BlockVarDecl* decl = + new BlockVarDecl(SourceLocation(),NULL,QualType(),None,NULL); + + decl->VarDecl::ReadImpl(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// FileVarDecl Serialization. +//===----------------------------------------------------------------------===// + +FileVarDecl* FileVarDecl::CreateImpl(Deserializer& D) { + FileVarDecl* decl = + new FileVarDecl(SourceLocation(),NULL,QualType(),None,NULL); + + decl->VarDecl::ReadImpl(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// ParmDecl Serialization. +//===----------------------------------------------------------------------===// + +void ParmVarDecl::EmitImpl(llvm::Serializer& S) const { + VarDecl::EmitImpl(S); + S.EmitInt(getObjCDeclQualifier()); // From ParmVarDecl. +} + +ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D) { + ParmVarDecl* decl = + new ParmVarDecl(SourceLocation(),NULL,QualType(),None,NULL); + + decl->VarDecl::ReadImpl(D); + decl->objcDeclQualifier = static_cast(D.ReadInt()); + + return decl; +} + +//===----------------------------------------------------------------------===// +// EnumDecl Serialization. +//===----------------------------------------------------------------------===// + +void EnumDecl::EmitImpl(Serializer& S) const { + ScopedDecl::EmitInRec(S); + S.EmitBool(isDefinition()); + S.Emit(IntegerType); + S.BatchEmitOwnedPtrs(ElementList,getNextDeclarator()); +} + +EnumDecl* EnumDecl::CreateImpl(Deserializer& D) { + EnumDecl* decl = new EnumDecl(SourceLocation(),NULL,NULL); + + decl->ScopedDecl::ReadInRec(D); + decl->setDefinition(D.ReadBool()); + decl->IntegerType = QualType::ReadVal(D); + + Decl* next_declarator; + Decl* Elist; + + D.BatchReadOwnedPtrs(Elist,next_declarator); + + decl->ElementList = cast_or_null(Elist); + decl->setNextDeclarator(cast_or_null(next_declarator)); + + return decl; +} + +//===----------------------------------------------------------------------===// +// EnumConstantDecl Serialization. +//===----------------------------------------------------------------------===// + +void EnumConstantDecl::EmitImpl(Serializer& S) const { + S.Emit(Val); + ValueDecl::EmitInRec(S); + S.BatchEmitOwnedPtrs(getNextDeclarator(),Init); +} + +EnumConstantDecl* EnumConstantDecl::CreateImpl(Deserializer& D) { + llvm::APSInt val(1); + D.Read(val); + + EnumConstantDecl* decl = + new EnumConstantDecl(SourceLocation(),NULL,QualType(),NULL, + val,NULL); + + decl->ValueDecl::ReadInRec(D); + + Decl* next_declarator; + + D.BatchReadOwnedPtrs(next_declarator,decl->Init); + + decl->setNextDeclarator(cast_or_null(next_declarator)); + + return decl; +} + +//===----------------------------------------------------------------------===// +// FieldDecl Serialization. +//===----------------------------------------------------------------------===// + +void FieldDecl::EmitImpl(Serializer& S) const { + S.Emit(getType()); + NamedDecl::EmitInRec(S); + S.EmitOwnedPtr(BitWidth); +} + +FieldDecl* FieldDecl::CreateImpl(Deserializer& D) { + FieldDecl* decl = new FieldDecl(SourceLocation(),NULL,QualType()); + decl->DeclType.ReadBackpatch(D); + decl->ReadInRec(D); + decl->BitWidth = D.ReadOwnedPtr(); + return decl; +} + +//===----------------------------------------------------------------------===// +// FunctionDecl Serialization. +//===----------------------------------------------------------------------===// + +void FunctionDecl::EmitImpl(Serializer& S) const { + S.EmitInt(SClass); // From FunctionDecl. + S.EmitBool(IsInline); // From FunctionDecl. + ValueDecl::EmitInRec(S); + S.EmitPtr(DeclChain); + + // NOTE: We do not need to serialize out the number of parameters, because + // that is encoded in the type (accessed via getNumParams()). + + if (ParamInfo != NULL) { + S.EmitBool(true); + S.BatchEmitOwnedPtrs(getNumParams(),&ParamInfo[0], Body, + getNextDeclarator()); + } + else { + S.EmitBool(false); + S.BatchEmitOwnedPtrs(Body,getNextDeclarator()); + } +} + +FunctionDecl* FunctionDecl::CreateImpl(Deserializer& D) { + StorageClass SClass = static_cast(D.ReadInt()); + bool IsInline = D.ReadBool(); + + FunctionDecl* decl = + new FunctionDecl(SourceLocation(),NULL,QualType(),SClass, IsInline, 0); + + decl->ValueDecl::ReadInRec(D); + D.ReadPtr(decl->DeclChain); + + Decl* next_declarator; + + bool hasParamDecls = D.ReadBool(); + + decl->ParamInfo = hasParamDecls + ? new ParmVarDecl*[decl->getNumParams()] + : NULL; + + if (hasParamDecls) + D.BatchReadOwnedPtrs(decl->getNumParams(), + reinterpret_cast(&decl->ParamInfo[0]), + decl->Body, next_declarator); + else + D.BatchReadOwnedPtrs(decl->Body, next_declarator); + + decl->setNextDeclarator(cast_or_null(next_declarator)); + + return decl; +} + +//===----------------------------------------------------------------------===// +// RecordDecl Serialization. +//===----------------------------------------------------------------------===// + +void RecordDecl::EmitImpl(Serializer& S) const { + ScopedDecl::EmitInRec(S); + S.EmitBool(isDefinition()); + S.EmitBool(hasFlexibleArrayMember()); + S.EmitSInt(getNumMembers()); + if (getNumMembers() > 0) { + assert (Members); + S.BatchEmitOwnedPtrs((unsigned) getNumMembers(), + (Decl**) &Members[0],getNextDeclarator()); + } + else + ScopedDecl::EmitOutRec(S); +} + +RecordDecl* RecordDecl::CreateImpl(Decl::Kind DK, Deserializer& D) { + RecordDecl* decl = new RecordDecl(DK,SourceLocation(),NULL,NULL); + + decl->ScopedDecl::ReadInRec(D); + decl->setDefinition(D.ReadBool()); + decl->setHasFlexibleArrayMember(D.ReadBool()); + decl->NumMembers = D.ReadSInt(); + + if (decl->getNumMembers() > 0) { + Decl* next_declarator; + decl->Members = new FieldDecl*[(unsigned) decl->getNumMembers()]; + + D.BatchReadOwnedPtrs((unsigned) decl->getNumMembers(), + (Decl**) &decl->Members[0], + next_declarator); + + decl->setNextDeclarator(cast_or_null(next_declarator)); + } + else + decl->ScopedDecl::ReadOutRec(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// TypedefDecl Serialization. +//===----------------------------------------------------------------------===// + +void TypedefDecl::EmitImpl(Serializer& S) const { + S.Emit(UnderlyingType); + ScopedDecl::EmitInRec(S); + ScopedDecl::EmitOutRec(S); +} + +TypedefDecl* TypedefDecl::CreateImpl(Deserializer& D) { + QualType T = QualType::ReadVal(D); + + TypedefDecl* decl = new TypedefDecl(SourceLocation(),NULL,T,NULL); + + decl->ScopedDecl::ReadInRec(D); + decl->ScopedDecl::ReadOutRec(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// LinkageSpec Serialization. +//===----------------------------------------------------------------------===// + +void LinkageSpecDecl::EmitInRec(Serializer& S) const { + Decl::EmitInRec(S); + S.EmitInt(getLanguage()); + S.EmitPtr(D); +} + +void LinkageSpecDecl::ReadInRec(Deserializer& D) { + Decl::ReadInRec(D); + Language = static_cast(D.ReadInt()); + D.ReadPtr(this->D); +} + +//===----------------------------------------------------------------------===// +// FileScopeAsm Serialization. +//===----------------------------------------------------------------------===// + +void FileScopeAsmDecl::EmitImpl(llvm::Serializer& S) const +{ + Decl::EmitInRec(S); + S.EmitOwnedPtr(AsmString); +} + +FileScopeAsmDecl* FileScopeAsmDecl::CreateImpl(Deserializer& D) { + FileScopeAsmDecl* decl = new FileScopeAsmDecl(SourceLocation(), 0); + + decl->Decl::ReadInRec(D); + decl->AsmString = cast(D.ReadOwnedPtr()); +// D.ReadOwnedPtr(D.ReadOwnedPtr())<#T * * Ptr#>, <#bool AutoRegister#>)(decl->AsmString); + + return decl; +} diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp new file mode 100644 index 00000000000..11fcc419a51 --- /dev/null +++ b/clang/lib/AST/Expr.cpp @@ -0,0 +1,1391 @@ +//===--- Expr.cpp - Expression AST Node Implementation --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expr class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +StringLiteral::StringLiteral(const char *strData, unsigned byteLength, + bool Wide, QualType t, SourceLocation firstLoc, + SourceLocation lastLoc) : + Expr(StringLiteralClass, t) { + // OPTIMIZE: could allocate this appended to the StringLiteral. + char *AStrData = new char[byteLength]; + memcpy(AStrData, strData, byteLength); + StrData = AStrData; + ByteLength = byteLength; + IsWide = Wide; + firstTokLoc = firstLoc; + lastTokLoc = lastLoc; +} + +StringLiteral::~StringLiteral() { + delete[] StrData; +} + +bool UnaryOperator::isPostfix(Opcode Op) { + switch (Op) { + case PostInc: + case PostDec: + return true; + default: + return false; + } +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "sizeof" or "[pre]++". +const char *UnaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown unary operator"); + case PostInc: return "++"; + case PostDec: return "--"; + case PreInc: return "++"; + case PreDec: return "--"; + case AddrOf: return "&"; + case Deref: return "*"; + case Plus: return "+"; + case Minus: return "-"; + case Not: return "~"; + case LNot: return "!"; + case Real: return "__real"; + case Imag: return "__imag"; + case SizeOf: return "sizeof"; + case AlignOf: return "alignof"; + case Extension: return "__extension__"; + case OffsetOf: return "__builtin_offsetof"; + } +} + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + + +CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t, + SourceLocation rparenloc) + : Expr(CallExprClass, t), NumArgs(numargs) { + SubExprs = new Expr*[numargs+1]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = args[i]; + RParenLoc = rparenloc; +} + +/// setNumArgs - This changes the number of arguments present in this call. +/// Any orphaned expressions are deleted by this, and any new operands are set +/// to null. +void CallExpr::setNumArgs(unsigned NumArgs) { + // No change, just return. + if (NumArgs == getNumArgs()) return; + + // If shrinking # arguments, just delete the extras and forgot them. + if (NumArgs < getNumArgs()) { + for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) + delete getArg(i); + this->NumArgs = NumArgs; + return; + } + + // Otherwise, we are growing the # arguments. New an bigger argument array. + Expr **NewSubExprs = new Expr*[NumArgs+1]; + // Copy over args. + for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) + NewSubExprs[i] = SubExprs[i]; + // Null out new args. + for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) + NewSubExprs[i] = 0; + + delete[] SubExprs; + SubExprs = NewSubExprs; + this->NumArgs = NumArgs; +} + +bool CallExpr::isBuiltinConstantExpr() const { + // All simple function calls (e.g. func()) are implicitly cast to pointer to + // function. As a result, we try and obtain the DeclRefExpr from the + // ImplicitCastExpr. + const ImplicitCastExpr *ICE = dyn_cast(getCallee()); + if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). + return false; + + const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); + if (!DRE) + return false; + + const FunctionDecl *FDecl = dyn_cast(DRE->getDecl()); + if (!FDecl) + return false; + + unsigned builtinID = FDecl->getIdentifier()->getBuiltinID(); + if (!builtinID) + return false; + + // We have a builtin that is a constant expression + if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString) + return true; + return false; +} + +bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const { + // The following enum mimics gcc's internal "typeclass.h" file. + enum gcc_type_class { + no_type_class = -1, + void_type_class, integer_type_class, char_type_class, + enumeral_type_class, boolean_type_class, + pointer_type_class, reference_type_class, offset_type_class, + real_type_class, complex_type_class, + function_type_class, method_type_class, + record_type_class, union_type_class, + array_type_class, string_type_class, + lang_type_class + }; + Result.setIsSigned(true); + + // All simple function calls (e.g. func()) are implicitly cast to pointer to + // function. As a result, we try and obtain the DeclRefExpr from the + // ImplicitCastExpr. + const ImplicitCastExpr *ICE = dyn_cast(getCallee()); + if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). + return false; + const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); + if (!DRE) + return false; + + // We have a DeclRefExpr. + if (strcmp(DRE->getDecl()->getName(), "__builtin_classify_type") == 0) { + // If no argument was supplied, default to "no_type_class". This isn't + // ideal, however it's what gcc does. + Result = static_cast(no_type_class); + if (NumArgs >= 1) { + QualType argType = getArg(0)->getType(); + + if (argType->isVoidType()) + Result = void_type_class; + else if (argType->isEnumeralType()) + Result = enumeral_type_class; + else if (argType->isBooleanType()) + Result = boolean_type_class; + else if (argType->isCharType()) + Result = string_type_class; // gcc doesn't appear to use char_type_class + else if (argType->isIntegerType()) + Result = integer_type_class; + else if (argType->isPointerType()) + Result = pointer_type_class; + else if (argType->isReferenceType()) + Result = reference_type_class; + else if (argType->isRealType()) + Result = real_type_class; + else if (argType->isComplexType()) + Result = complex_type_class; + else if (argType->isFunctionType()) + Result = function_type_class; + else if (argType->isStructureType()) + Result = record_type_class; + else if (argType->isUnionType()) + Result = union_type_class; + else if (argType->isArrayType()) + Result = array_type_class; + else if (argType->isUnionType()) + Result = union_type_class; + else // FIXME: offset_type_class, method_type_class, & lang_type_class? + assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); + } + return true; + } + return false; +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "<<=". +const char *BinaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown binary operator"); + case Mul: return "*"; + case Div: return "/"; + case Rem: return "%"; + case Add: return "+"; + case Sub: return "-"; + case Shl: return "<<"; + case Shr: return ">>"; + case LT: return "<"; + case GT: return ">"; + case LE: return "<="; + case GE: return ">="; + case EQ: return "=="; + case NE: return "!="; + case And: return "&"; + case Xor: return "^"; + case Or: return "|"; + case LAnd: return "&&"; + case LOr: return "||"; + case Assign: return "="; + case MulAssign: return "*="; + case DivAssign: return "/="; + case RemAssign: return "%="; + case AddAssign: return "+="; + case SubAssign: return "-="; + case ShlAssign: return "<<="; + case ShrAssign: return ">>="; + case AndAssign: return "&="; + case XorAssign: return "^="; + case OrAssign: return "|="; + case Comma: return ","; + } +} + +InitListExpr::InitListExpr(SourceLocation lbraceloc, + Expr **initexprs, unsigned numinits, + SourceLocation rbraceloc) + : Expr(InitListExprClass, QualType()) + , NumInits(numinits) + , LBraceLoc(lbraceloc) + , RBraceLoc(rbraceloc) +{ + InitExprs = new Expr*[numinits]; + for (unsigned i = 0; i != numinits; i++) + InitExprs[i] = initexprs[i]; +} + +//===----------------------------------------------------------------------===// +// Generic Expression Routines +//===----------------------------------------------------------------------===// + +/// hasLocalSideEffect - Return true if this immediate expression has side +/// effects, not counting any sub-expressions. +bool Expr::hasLocalSideEffect() const { + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: + return cast(this)->getSubExpr()->hasLocalSideEffect(); + case UnaryOperatorClass: { + const UnaryOperator *UO = cast(this); + + switch (UO->getOpcode()) { + default: return false; + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + return true; // ++/-- + + case UnaryOperator::Deref: + // Dereferencing a volatile pointer is a side-effect. + return getType().isVolatileQualified(); + case UnaryOperator::Real: + case UnaryOperator::Imag: + // accessing a piece of a volatile complex is a side-effect. + return UO->getSubExpr()->getType().isVolatileQualified(); + + case UnaryOperator::Extension: + return UO->getSubExpr()->hasLocalSideEffect(); + } + } + case BinaryOperatorClass: { + const BinaryOperator *BinOp = cast(this); + // Consider comma to have side effects if the LHS and RHS both do. + if (BinOp->getOpcode() == BinaryOperator::Comma) + return BinOp->getLHS()->hasLocalSideEffect() && + BinOp->getRHS()->hasLocalSideEffect(); + + return BinOp->isAssignmentOp(); + } + case CompoundAssignOperatorClass: + return true; + + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(this); + return Exp->getCond()->hasLocalSideEffect() + || (Exp->getLHS() && Exp->getLHS()->hasLocalSideEffect()) + || (Exp->getRHS() && Exp->getRHS()->hasLocalSideEffect()); + } + + case MemberExprClass: + case ArraySubscriptExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // if is a side effect. + return getType().isVolatileQualified(); + + case CallExprClass: + // TODO: check attributes for pure/const. "void foo() { strlen("bar"); }" + // should warn. + return true; + case ObjCMessageExprClass: + return true; + + case CastExprClass: + // If this is a cast to void, check the operand. Otherwise, the result of + // the cast is unused. + if (getType()->isVoidType()) + return cast(this)->getSubExpr()->hasLocalSideEffect(); + return false; + } +} + +/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an +/// incomplete type other than void. Nonarray expressions that can be lvalues: +/// - name, where name must be a variable +/// - e[i] +/// - (e), where e must be an lvalue +/// - e.name, where e must be an lvalue +/// - e->name +/// - *e, the type of e cannot be a function type +/// - string-constant +/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension] +/// - reference type [C++ [expr]] +/// +Expr::isLvalueResult Expr::isLvalue() const { + // first, check the type (C99 6.3.2.1) + if (TR->isFunctionType()) // from isObjectType() + return LV_NotObjectType; + + // Allow qualified void which is an incomplete type other than void (yuck). + if (TR->isVoidType() && !TR.getCanonicalType().getCVRQualifiers()) + return LV_IncompleteVoidType; + + if (TR->isReferenceType()) // C++ [expr] + return LV_Valid; + + // the type looks fine, now check the expression + switch (getStmtClass()) { + case StringLiteralClass: // C99 6.5.1p4 + return LV_Valid; + case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2)))) + // For vectors, make sure base is an lvalue (i.e. not a function call). + if (cast(this)->getBase()->getType()->isVectorType()) + return cast(this)->getBase()->isLvalue(); + return LV_Valid; + case DeclRefExprClass: // C99 6.5.1p2 + if (isa(cast(this)->getDecl())) + return LV_Valid; + break; + case MemberExprClass: { // C99 6.5.2.3p4 + const MemberExpr *m = cast(this); + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(); + } + case UnaryOperatorClass: + if (cast(this)->getOpcode() == UnaryOperator::Deref) + return LV_Valid; // C99 6.5.3p4 + + if (cast(this)->getOpcode() == UnaryOperator::Real || + cast(this)->getOpcode() == UnaryOperator::Imag) + return cast(this)->getSubExpr()->isLvalue(); // GNU. + break; + case ParenExprClass: // C99 6.5.1p5 + return cast(this)->getSubExpr()->isLvalue(); + case CompoundLiteralExprClass: // C99 6.5.2.5p5 + return LV_Valid; + case OCUVectorElementExprClass: + if (cast(this)->containsDuplicateElements()) + return LV_DuplicateVectorComponents; + return LV_Valid; + case ObjCIvarRefExprClass: // ObjC instance variables are lvalues. + return LV_Valid; + case PreDefinedExprClass: + return LV_Valid; + default: + break; + } + return LV_InvalidExpression; +} + +/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, +/// does not have an incomplete type, does not have a const-qualified type, and +/// if it is a structure or union, does not have any member (including, +/// recursively, any member or element of all contained aggregates or unions) +/// with a const-qualified type. +Expr::isModifiableLvalueResult Expr::isModifiableLvalue() const { + isLvalueResult lvalResult = isLvalue(); + + switch (lvalResult) { + case LV_Valid: break; + case LV_NotObjectType: return MLV_NotObjectType; + case LV_IncompleteVoidType: return MLV_IncompleteVoidType; + case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; + case LV_InvalidExpression: return MLV_InvalidExpression; + } + if (TR.isConstQualified()) + return MLV_ConstQualified; + if (TR->isArrayType()) + return MLV_ArrayType; + if (TR->isIncompleteType()) + return MLV_IncompleteType; + + if (const RecordType *r = dyn_cast(TR.getCanonicalType())) { + if (r->hasConstFields()) + return MLV_ConstQualified; + } + return MLV_Valid; +} + +/// hasGlobalStorage - Return true if this expression has static storage +/// duration. This means that the address of this expression is a link-time +/// constant. +bool Expr::hasGlobalStorage() const { + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: + return cast(this)->getSubExpr()->hasGlobalStorage(); + case ImplicitCastExprClass: + return cast(this)->getSubExpr()->hasGlobalStorage(); + case CompoundLiteralExprClass: + return cast(this)->isFileScope(); + case DeclRefExprClass: { + const Decl *D = cast(this)->getDecl(); + if (const VarDecl *VD = dyn_cast(D)) + return VD->hasGlobalStorage(); + return false; + } + case MemberExprClass: { + const MemberExpr *M = cast(this); + return !M->isArrow() && M->getBase()->hasGlobalStorage(); + } + case ArraySubscriptExprClass: + return cast(this)->getBase()->hasGlobalStorage(); + case PreDefinedExprClass: + return true; + } +} + +Expr* Expr::IgnoreParens() { + Expr* E = this; + while (ParenExpr* P = dyn_cast(E)) + E = P->getSubExpr(); + + return E; +} + +/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr +/// or CastExprs or ImplicitCastExprs, returning their operand. +Expr *Expr::IgnoreParenCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast(E)) + E = P->getSubExpr(); + else if (CastExpr *P = dyn_cast(E)) + E = P->getSubExpr(); + else if (ImplicitCastExpr *P = dyn_cast(E)) + E = P->getSubExpr(); + else + return E; + } +} + + +bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { + switch (getStmtClass()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case ParenExprClass: + return cast(this)->getSubExpr()->isConstantExpr(Ctx, Loc); + case StringLiteralClass: + case ObjCStringLiteralClass: + case FloatingLiteralClass: + case IntegerLiteralClass: + case CharacterLiteralClass: + case ImaginaryLiteralClass: + case TypesCompatibleExprClass: + case CXXBoolLiteralExprClass: + return true; + case CallExprClass: { + const CallExpr *CE = cast(this); + llvm::APSInt Result(32); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + if (CE->isBuiltinClassifyType(Result)) + return true; + if (CE->isBuiltinConstantExpr()) + return true; + if (Loc) *Loc = getLocStart(); + return false; + } + case DeclRefExprClass: { + const Decl *D = cast(this)->getDecl(); + // Accept address of function. + if (isa(D) || isa(D)) + return true; + if (Loc) *Loc = getLocStart(); + if (isa(D)) + return TR->isArrayType(); + return false; + } + case CompoundLiteralExprClass: + if (Loc) *Loc = getLocStart(); + // Allow "(int []){2,4}", since the array will be converted to a pointer. + // Allow "(vector type){2,4}" since the elements are all constant. + return TR->isArrayType() || TR->isVectorType(); + case UnaryOperatorClass: { + const UnaryOperator *Exp = cast(this); + + // C99 6.6p9 + if (Exp->getOpcode() == UnaryOperator::AddrOf) { + if (!Exp->getSubExpr()->hasGlobalStorage()) { + if (Loc) *Loc = getLocStart(); + return false; + } + return true; + } + + // Get the operand value. If this is sizeof/alignof, do not evalute the + // operand. This affects C99 6.6p3. + if (!Exp->isSizeOfAlignOfOp() && + Exp->getOpcode() != UnaryOperator::OffsetOf && + !Exp->getSubExpr()->isConstantExpr(Ctx, Loc)) + return false; + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + case UnaryOperator::Extension: + return true; // FIXME: this is wrong. + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + case UnaryOperator::OffsetOf: + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + return true; + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + return true; + } + } + case SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast(this); + // alignof always evaluates to a constant. + if (Exp->isSizeOf() && !Exp->getArgumentType()->isVoidType() && + !Exp->getArgumentType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + return true; + } + case BinaryOperatorClass: { + const BinaryOperator *Exp = cast(this); + + // The LHS of a constant expr is always evaluated and needed. + if (!Exp->getLHS()->isConstantExpr(Ctx, Loc)) + return false; + + if (!Exp->getRHS()->isConstantExpr(Ctx, Loc)) + return false; + return true; + } + case ImplicitCastExprClass: + case CastExprClass: { + const Expr *SubExpr; + SourceLocation CastLoc; + if (const CastExpr *C = dyn_cast(this)) { + SubExpr = C->getSubExpr(); + CastLoc = C->getLParenLoc(); + } else { + SubExpr = cast(this)->getSubExpr(); + CastLoc = getLocStart(); + } + if (!SubExpr->isConstantExpr(Ctx, Loc)) { + if (Loc) *Loc = SubExpr->getLocStart(); + return false; + } + return true; + } + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(this); + if (!Exp->getCond()->isConstantExpr(Ctx, Loc) || + // Handle the GNU extension for missing LHS. + !(Exp->getLHS() && Exp->getLHS()->isConstantExpr(Ctx, Loc)) || + !Exp->getRHS()->isConstantExpr(Ctx, Loc)) + return false; + return true; + } + case InitListExprClass: { + const InitListExpr *Exp = cast(this); + unsigned numInits = Exp->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!Exp->getInit(i)->isConstantExpr(Ctx, Loc)) { + if (Loc) *Loc = Exp->getInit(i)->getLocStart(); + return false; + } + } + return true; + } + } +} + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. Note: With the introduction of VLA's in +/// C99 the result of the sizeof operator is no longer always a constant +/// expression. The generalization of the wording to include any subexpression +/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions +/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance, +/// "0 || f()" can be treated as a constant expression. In C90 this expression, +/// occurring in a context requiring a constant, would have been a constraint +/// violation. FIXME: This routine currently implements C90 semantics. +/// To properly implement C99 semantics this routine will need to evaluate +/// expressions involving operators previously mentioned. + +/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, +/// comma, etc +/// +/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not +/// permit this. This includes things like (int)1e1000 +/// +/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof +/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer +/// cast+dereference. +bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc, bool isEvaluated) const { + switch (getStmtClass()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case ParenExprClass: + return cast(this)->getSubExpr()-> + isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated); + case IntegerLiteralClass: + Result = cast(this)->getValue(); + break; + case CharacterLiteralClass: { + const CharacterLiteral *CL = cast(this); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = CL->getValue(); + Result.setIsUnsigned(!getType()->isSignedIntegerType()); + break; + } + case TypesCompatibleExprClass: { + const TypesCompatibleExpr *TCE = cast(this); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = Ctx.typesAreCompatible(TCE->getArgType1(), TCE->getArgType2()); + break; + } + case CallExprClass: { + const CallExpr *CE = cast(this); + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + if (CE->isBuiltinClassifyType(Result)) + break; + if (Loc) *Loc = getLocStart(); + return false; + } + case DeclRefExprClass: + if (const EnumConstantDecl *D = + dyn_cast(cast(this)->getDecl())) { + Result = D->getInitVal(); + break; + } + if (Loc) *Loc = getLocStart(); + return false; + case UnaryOperatorClass: { + const UnaryOperator *Exp = cast(this); + + // Get the operand value. If this is sizeof/alignof, do not evalute the + // operand. This affects C99 6.6p3. + if (!Exp->isSizeOfAlignOfOp() && !Exp->isOffsetOfOp() && + !Exp->getSubExpr()->isIntegerConstantExpr(Result, Ctx, Loc,isEvaluated)) + return false; + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + case UnaryOperator::Extension: + return true; // FIXME: this is wrong. + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + // Return the result in the right width. + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (Exp->getSubExpr()->getType()->isVoidType()) { + Result = 1; + break; + } + + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + + // Get information about the size or align. + if (Exp->getSubExpr()->getType()->isFunctionType()) { + // GCC extension: sizeof(function) = 1. + Result = Exp->getOpcode() == UnaryOperator::AlignOf ? 4 : 1; + } else { + unsigned CharSize = Ctx.Target.getCharWidth(); + if (Exp->getOpcode() == UnaryOperator::AlignOf) + Result = Ctx.getTypeAlign(Exp->getSubExpr()->getType()) / CharSize; + else + Result = Ctx.getTypeSize(Exp->getSubExpr()->getType()) / CharSize; + } + break; + case UnaryOperator::LNot: { + bool Val = Result == 0; + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + Result = Val; + break; + } + case UnaryOperator::Plus: + break; + case UnaryOperator::Minus: + Result = -Result; + break; + case UnaryOperator::Not: + Result = ~Result; + break; + case UnaryOperator::OffsetOf: + Result = Exp->evaluateOffsetOf(Ctx); + } + break; + } + case SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast(this); + + // Return the result in the right width. + Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (Exp->getArgumentType()->isVoidType()) { + Result = 1; + break; + } + + // alignof always evaluates to a constant, sizeof does if arg is not VLA. + if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + + // Get information about the size or align. + if (Exp->getArgumentType()->isFunctionType()) { + // GCC extension: sizeof(function) = 1. + Result = Exp->isSizeOf() ? 1 : 4; + } else { + unsigned CharSize = Ctx.Target.getCharWidth(); + if (Exp->isSizeOf()) + Result = Ctx.getTypeSize(Exp->getArgumentType()) / CharSize; + else + Result = Ctx.getTypeAlign(Exp->getArgumentType()) / CharSize; + } + break; + } + case BinaryOperatorClass: { + const BinaryOperator *Exp = cast(this); + + // The LHS of a constant expr is always evaluated and needed. + if (!Exp->getLHS()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + + llvm::APSInt RHS(Result); + + // The short-circuiting &&/|| operators don't necessarily evaluate their + // RHS. Make sure to pass isEvaluated down correctly. + if (Exp->isLogicalOp()) { + bool RHSEval; + if (Exp->getOpcode() == BinaryOperator::LAnd) + RHSEval = Result != 0; + else { + assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical"); + RHSEval = Result == 0; + } + + if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, + isEvaluated & RHSEval)) + return false; + } else { + if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, isEvaluated)) + return false; + } + + switch (Exp->getOpcode()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case BinaryOperator::Mul: + Result *= RHS; + break; + case BinaryOperator::Div: + if (RHS == 0) { + if (!isEvaluated) break; + if (Loc) *Loc = getLocStart(); + return false; + } + Result /= RHS; + break; + case BinaryOperator::Rem: + if (RHS == 0) { + if (!isEvaluated) break; + if (Loc) *Loc = getLocStart(); + return false; + } + Result %= RHS; + break; + case BinaryOperator::Add: Result += RHS; break; + case BinaryOperator::Sub: Result -= RHS; break; + case BinaryOperator::Shl: + Result <<= + static_cast(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::Shr: + Result >>= + static_cast(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::LT: Result = Result < RHS; break; + case BinaryOperator::GT: Result = Result > RHS; break; + case BinaryOperator::LE: Result = Result <= RHS; break; + case BinaryOperator::GE: Result = Result >= RHS; break; + case BinaryOperator::EQ: Result = Result == RHS; break; + case BinaryOperator::NE: Result = Result != RHS; break; + case BinaryOperator::And: Result &= RHS; break; + case BinaryOperator::Xor: Result ^= RHS; break; + case BinaryOperator::Or: Result |= RHS; break; + case BinaryOperator::LAnd: + Result = Result != 0 && RHS != 0; + break; + case BinaryOperator::LOr: + Result = Result != 0 || RHS != 0; + break; + + case BinaryOperator::Comma: + // C99 6.6p3: "shall not contain assignment, ..., or comma operators, + // *except* when they are contained within a subexpression that is not + // evaluated". Note that Assignment can never happen due to constraints + // on the LHS subexpr, so we don't need to check it here. + if (isEvaluated) { + if (Loc) *Loc = getLocStart(); + return false; + } + + // The result of the constant expr is the RHS. + Result = RHS; + return true; + } + + assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!"); + break; + } + case ImplicitCastExprClass: + case CastExprClass: { + const Expr *SubExpr; + SourceLocation CastLoc; + if (const CastExpr *C = dyn_cast(this)) { + SubExpr = C->getSubExpr(); + CastLoc = C->getLParenLoc(); + } else { + SubExpr = cast(this)->getSubExpr(); + CastLoc = getLocStart(); + } + + // C99 6.6p6: shall only convert arithmetic types to integer types. + if (!SubExpr->getType()->isArithmeticType() || + !getType()->isIntegerType()) { + if (Loc) *Loc = SubExpr->getLocStart(); + return false; + } + + uint32_t DestWidth = static_cast(Ctx.getTypeSize(getType())); + + // Handle simple integer->integer casts. + if (SubExpr->getType()->isIntegerType()) { + if (!SubExpr->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + + // Figure out if this is a truncate, extend or noop cast. + // If the input is signed, do a sign extend, noop, or truncate. + if (getType()->isBooleanType()) { + // Conversion to bool compares against zero. + Result = Result != 0; + Result.zextOrTrunc(DestWidth); + } else if (SubExpr->getType()->isSignedIntegerType()) + Result.sextOrTrunc(DestWidth); + else // If the input is unsigned, do a zero extend, noop, or truncate. + Result.zextOrTrunc(DestWidth); + break; + } + + // Allow floating constants that are the immediate operands of casts or that + // are parenthesized. + const Expr *Operand = SubExpr; + while (const ParenExpr *PE = dyn_cast(Operand)) + Operand = PE->getSubExpr(); + + // If this isn't a floating literal, we can't handle it. + const FloatingLiteral *FL = dyn_cast(Operand); + if (!FL) { + if (Loc) *Loc = Operand->getLocStart(); + return false; + } + + // If the destination is boolean, compare against zero. + if (getType()->isBooleanType()) { + Result = !FL->getValue().isZero(); + Result.zextOrTrunc(DestWidth); + break; + } + + // Determine whether we are converting to unsigned or signed. + bool DestSigned = getType()->isSignedIntegerType(); + + // TODO: Warn on overflow, but probably not here: isIntegerConstantExpr can + // be called multiple times per AST. + uint64_t Space[4]; + (void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned, + llvm::APFloat::rmTowardZero); + Result = llvm::APInt(DestWidth, 4, Space); + break; + } + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(this); + + if (!Exp->getCond()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + + const Expr *TrueExp = Exp->getLHS(); + const Expr *FalseExp = Exp->getRHS(); + if (Result == 0) std::swap(TrueExp, FalseExp); + + // Evaluate the false one first, discard the result. + if (FalseExp && !FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false)) + return false; + // Evalute the true one, capture the result. + if (TrueExp && + !TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + break; + } + } + + // Cases that are valid constant exprs fall through to here. + Result.setIsUnsigned(getType()->isUnsignedIntegerType()); + return true; +} + +/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an +/// integer constant expression with the value zero, or if this is one that is +/// cast to void*. +bool Expr::isNullPointerConstant(ASTContext &Ctx) const { + // Strip off a cast to void*, if it exists. + if (const CastExpr *CE = dyn_cast(this)) { + // Check that it is a cast to void*. + if (const PointerType *PT = CE->getType()->getAsPointerType()) { + QualType Pointee = PT->getPointeeType(); + if (Pointee.getCVRQualifiers() == 0 && + Pointee->isVoidType() && // to void* + CE->getSubExpr()->getType()->isIntegerType()) // from int. + return CE->getSubExpr()->isNullPointerConstant(Ctx); + } + } else if (const ImplicitCastExpr *ICE = dyn_cast(this)) { + // Ignore the ImplicitCastExpr type entirely. + return ICE->getSubExpr()->isNullPointerConstant(Ctx); + } else if (const ParenExpr *PE = dyn_cast(this)) { + // Accept ((void*)0) as a null pointer constant, as many other + // implementations do. + return PE->getSubExpr()->isNullPointerConstant(Ctx); + } + + // This expression must be an integer type. + if (!getType()->isIntegerType()) + return false; + + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. + llvm::APSInt Val(32); + return isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0; +} + +unsigned OCUVectorElementExpr::getNumElements() const { + return strlen(Accessor.getName()); +} + + +/// getComponentType - Determine whether the components of this access are +/// "point" "color" or "texture" elements. +OCUVectorElementExpr::ElementType +OCUVectorElementExpr::getElementType() const { + // derive the component type, no need to waste space. + const char *compStr = Accessor.getName(); + + if (OCUVectorType::getPointAccessorIdx(*compStr) != -1) return Point; + if (OCUVectorType::getColorAccessorIdx(*compStr) != -1) return Color; + + assert(OCUVectorType::getTextureAccessorIdx(*compStr) != -1 && + "getComponentType(): Illegal accessor"); + return Texture; +} + +/// containsDuplicateElements - Return true if any element access is +/// repeated. +bool OCUVectorElementExpr::containsDuplicateElements() const { + const char *compStr = Accessor.getName(); + unsigned length = strlen(compStr); + + for (unsigned i = 0; i < length-1; i++) { + const char *s = compStr+i; + for (const char c = *s++; *s; s++) + if (c == *s) + return true; + } + return false; +} + +/// getEncodedElementAccess - We encode fields with two bits per component. +unsigned OCUVectorElementExpr::getEncodedElementAccess() const { + const char *compStr = Accessor.getName(); + unsigned length = getNumElements(); + + unsigned Result = 0; + + while (length--) { + Result <<= 2; + int Idx = OCUVectorType::getAccessorIdx(compStr[length]); + assert(Idx != -1 && "Invalid accessor letter"); + Result |= Idx; + } + return Result; +} + +// constructor for instance messages. +ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + MethodProto(mproto), ClassName(0) { + NumArgs = nargs; + SubExprs = new Expr*[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(IdentifierInfo *clsName, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + MethodProto(mproto), ClassName(clsName) { + NumArgs = nargs; + SubExprs = new Expr*[NumArgs+1]; + SubExprs[RECEIVER] = 0; + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + + +bool ChooseExpr::isConditionTrue(ASTContext &C) const { + llvm::APSInt CondVal(32); + bool IsConst = getCond()->isIntegerConstantExpr(CondVal, C); + assert(IsConst && "Condition of choose expr must be i-c-e"); IsConst=IsConst; + return CondVal != 0; +} + +static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E) +{ + if (const MemberExpr *ME = dyn_cast(E)) { + QualType Ty = ME->getBase()->getType(); + + RecordDecl *RD = Ty->getAsRecordType()->getDecl(); + const ASTRecordLayout &RL = C.getASTRecordLayout(RD); + FieldDecl *FD = ME->getMemberDecl(); + + // FIXME: This is linear time. + unsigned i = 0, e = 0; + for (i = 0, e = RD->getNumMembers(); i != e; i++) { + if (RD->getMember(i) == FD) + break; + } + + return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase()); + } else if (const ArraySubscriptExpr *ASE = dyn_cast(E)) { + const Expr *Base = ASE->getBase(); + llvm::APSInt Idx(32); + bool ICE = ASE->getIdx()->isIntegerConstantExpr(Idx, C); + assert(ICE && "Array index is not a constant integer!"); + + int64_t size = C.getTypeSize(ASE->getType()); + size *= Idx.getSExtValue(); + + return size + evaluateOffsetOf(C, Base); + } else if (isa(E)) + return 0; + + assert(0 && "Unknown offsetof subexpression!"); + return 0; +} + +int64_t UnaryOperator::evaluateOffsetOf(ASTContext& C) const +{ + assert(Opc == OffsetOf && "Unary operator not offsetof!"); + + unsigned CharSize = C.Target.getCharWidth(); + return ::evaluateOffsetOf(C, Val) / CharSize; +} + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +// DeclRefExpr +Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); } + +// ObjCIvarRefExpr +Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCIvarRefExpr::child_end() { return child_iterator(); } + +// PreDefinedExpr +Stmt::child_iterator PreDefinedExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator PreDefinedExpr::child_end() { return child_iterator(); } + +// IntegerLiteral +Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); } + +// CharacterLiteral +Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); } + +// FloatingLiteral +Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); } + +// ImaginaryLiteral +Stmt::child_iterator ImaginaryLiteral::child_begin() { + return reinterpret_cast(&Val); +} +Stmt::child_iterator ImaginaryLiteral::child_end() { + return reinterpret_cast(&Val)+1; +} + +// StringLiteral +Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); } + +// ParenExpr +Stmt::child_iterator ParenExpr::child_begin() { + return reinterpret_cast(&Val); +} +Stmt::child_iterator ParenExpr::child_end() { + return reinterpret_cast(&Val)+1; +} + +// UnaryOperator +Stmt::child_iterator UnaryOperator::child_begin() { + return reinterpret_cast(&Val); +} +Stmt::child_iterator UnaryOperator::child_end() { + return reinterpret_cast(&Val+1); +} + +// SizeOfAlignOfTypeExpr +Stmt::child_iterator SizeOfAlignOfTypeExpr::child_begin() { + // If the type is a VLA type (and not a typedef), the size expression of the + // VLA needs to be treated as an executable expression. + if (VariableArrayType* T = dyn_cast(Ty.getTypePtr())) + return child_iterator(T); + else + return child_iterator(); +} +Stmt::child_iterator SizeOfAlignOfTypeExpr::child_end() { + return child_iterator(); +} + +// ArraySubscriptExpr +Stmt::child_iterator ArraySubscriptExpr::child_begin() { + return reinterpret_cast(&SubExprs); +} +Stmt::child_iterator ArraySubscriptExpr::child_end() { + return reinterpret_cast(&SubExprs)+END_EXPR; +} + +// CallExpr +Stmt::child_iterator CallExpr::child_begin() { + return reinterpret_cast(&SubExprs[0]); +} +Stmt::child_iterator CallExpr::child_end() { + return reinterpret_cast(&SubExprs[NumArgs+ARGS_START]); +} + +// MemberExpr +Stmt::child_iterator MemberExpr::child_begin() { + return reinterpret_cast(&Base); +} +Stmt::child_iterator MemberExpr::child_end() { + return reinterpret_cast(&Base)+1; +} + +// OCUVectorElementExpr +Stmt::child_iterator OCUVectorElementExpr::child_begin() { + return reinterpret_cast(&Base); +} +Stmt::child_iterator OCUVectorElementExpr::child_end() { + return reinterpret_cast(&Base)+1; +} + +// CompoundLiteralExpr +Stmt::child_iterator CompoundLiteralExpr::child_begin() { + return reinterpret_cast(&Init); +} +Stmt::child_iterator CompoundLiteralExpr::child_end() { + return reinterpret_cast(&Init)+1; +} + +// ImplicitCastExpr +Stmt::child_iterator ImplicitCastExpr::child_begin() { + return reinterpret_cast(&Op); +} +Stmt::child_iterator ImplicitCastExpr::child_end() { + return reinterpret_cast(&Op)+1; +} + +// CastExpr +Stmt::child_iterator CastExpr::child_begin() { + return reinterpret_cast(&Op); +} +Stmt::child_iterator CastExpr::child_end() { + return reinterpret_cast(&Op)+1; +} + +// BinaryOperator +Stmt::child_iterator BinaryOperator::child_begin() { + return reinterpret_cast(&SubExprs); +} +Stmt::child_iterator BinaryOperator::child_end() { + return reinterpret_cast(&SubExprs)+END_EXPR; +} + +// ConditionalOperator +Stmt::child_iterator ConditionalOperator::child_begin() { + return reinterpret_cast(&SubExprs); +} +Stmt::child_iterator ConditionalOperator::child_end() { + return reinterpret_cast(&SubExprs)+END_EXPR; +} + +// AddrLabelExpr +Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); } + +// StmtExpr +Stmt::child_iterator StmtExpr::child_begin() { + return reinterpret_cast(&SubStmt); +} +Stmt::child_iterator StmtExpr::child_end() { + return reinterpret_cast(&SubStmt)+1; +} + +// TypesCompatibleExpr +Stmt::child_iterator TypesCompatibleExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator TypesCompatibleExpr::child_end() { + return child_iterator(); +} + +// ChooseExpr +Stmt::child_iterator ChooseExpr::child_begin() { + return reinterpret_cast(&SubExprs); +} + +Stmt::child_iterator ChooseExpr::child_end() { + return reinterpret_cast(&SubExprs)+END_EXPR; +} + +// OverloadExpr +Stmt::child_iterator OverloadExpr::child_begin() { + return reinterpret_cast(&SubExprs[0]); +} +Stmt::child_iterator OverloadExpr::child_end() { + return reinterpret_cast(&SubExprs[NumExprs]); +} + +// VAArgExpr +Stmt::child_iterator VAArgExpr::child_begin() { + return reinterpret_cast(&Val); +} + +Stmt::child_iterator VAArgExpr::child_end() { + return reinterpret_cast(&Val)+1; +} + +// InitListExpr +Stmt::child_iterator InitListExpr::child_begin() { + return reinterpret_cast(&InitExprs[0]); +} +Stmt::child_iterator InitListExpr::child_end() { + return reinterpret_cast(&InitExprs[NumInits]); +} + +// ObjCStringLiteral +Stmt::child_iterator ObjCStringLiteral::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCStringLiteral::child_end() { + return child_iterator(); +} + +// ObjCEncodeExpr +Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } + +// ObjCSelectorExpr +Stmt::child_iterator ObjCSelectorExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCSelectorExpr::child_end() { + return child_iterator(); +} + +// ObjCProtocolExpr +Stmt::child_iterator ObjCProtocolExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCProtocolExpr::child_end() { + return child_iterator(); +} + +// ObjCMessageExpr +Stmt::child_iterator ObjCMessageExpr::child_begin() { + return reinterpret_cast(&SubExprs[0]); +} +Stmt::child_iterator ObjCMessageExpr::child_end() { + return reinterpret_cast(&SubExprs[getNumArgs()+ARGS_START]); +} + diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp new file mode 100644 index 00000000000..3bc32e75d87 --- /dev/null +++ b/clang/lib/AST/ExprCXX.cpp @@ -0,0 +1,47 @@ +//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the subclesses of Expr class declared in ExprCXX.h +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprCXX.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + + +// CXXCastExpr +Stmt::child_iterator CXXCastExpr::child_begin() { + return reinterpret_cast(&Op); +} +Stmt::child_iterator CXXCastExpr::child_end() { + return reinterpret_cast(&Op)+1; +} + +// CXXBoolLiteralExpr +Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXBoolLiteralExpr::child_end() { + return child_iterator(); +} + +// CXXThrowExpr +Stmt::child_iterator CXXThrowExpr::child_begin() { + return reinterpret_cast(&Op); +} +Stmt::child_iterator CXXThrowExpr::child_end() { + // If Op is 0, we are processing throw; which has no children. + if (Op == 0) + return reinterpret_cast(&Op)+0; + return reinterpret_cast(&Op)+1; +} diff --git a/clang/lib/AST/Makefile b/clang/lib/AST/Makefile new file mode 100644 index 00000000000..cdfc64cacaf --- /dev/null +++ b/clang/lib/AST/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/AST/Makefile ------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the AST library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangAST +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp new file mode 100644 index 00000000000..572280bc054 --- /dev/null +++ b/clang/lib/AST/Stmt.cpp @@ -0,0 +1,293 @@ +//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt class and statement subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Stmt.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/IdentifierTable.h" +using namespace clang; + +static struct StmtClassNameTable { + const char *Name; + unsigned Counter; + unsigned Size; +} StmtClassInfo[Stmt::lastExprConstant+1]; + +static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { + static bool Initialized = false; + if (Initialized) + return StmtClassInfo[E]; + + // Intialize the table on the first use. + Initialized = true; +#define STMT(N, CLASS, PARENT) \ + StmtClassInfo[N].Name = #CLASS; \ + StmtClassInfo[N].Size = sizeof(CLASS); +#include "clang/AST/StmtNodes.def" + + return StmtClassInfo[E]; +} + +const char *Stmt::getStmtClassName() const { + return getStmtInfoTableEntry(sClass).Name; +} + +void Stmt::PrintStats() { + // Ensure the table is primed. + getStmtInfoTableEntry(Stmt::NullStmtClass); + + unsigned sum = 0; + fprintf(stderr, "*** Stmt/Expr Stats:\n"); + for (int i = 0; i != Stmt::lastExprConstant+1; i++) { + if (StmtClassInfo[i].Name == 0) continue; + sum += StmtClassInfo[i].Counter; + } + fprintf(stderr, " %d stmts/exprs total.\n", sum); + sum = 0; + for (int i = 0; i != Stmt::lastExprConstant+1; i++) { + if (StmtClassInfo[i].Name == 0) continue; + fprintf(stderr, " %d %s, %d each (%d bytes)\n", + StmtClassInfo[i].Counter, StmtClassInfo[i].Name, + StmtClassInfo[i].Size, + StmtClassInfo[i].Counter*StmtClassInfo[i].Size); + sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size; + } + fprintf(stderr, "Total bytes = %d\n", sum); +} + +void Stmt::addStmtClass(StmtClass s) { + ++getStmtInfoTableEntry(s).Counter; +} + +static bool StatSwitch = false; + +bool Stmt::CollectingStats(bool enable) { + if (enable) StatSwitch = true; + return StatSwitch; +} + + +const char *LabelStmt::getName() const { + return getID()->getName(); +} + +// This is defined here to avoid polluting Stmt.h with importing Expr.h +SourceRange ReturnStmt::getSourceRange() const { + if (RetExpr) + return SourceRange(RetLoc, RetExpr->getLocEnd()); + else + return SourceRange(RetLoc); +} + +bool Stmt::hasImplicitControlFlow() const { + switch (sClass) { + default: + return false; + + case CallExprClass: + case ConditionalOperatorClass: + case ChooseExprClass: + case StmtExprClass: + case DeclStmtClass: + return true; + + case Stmt::BinaryOperatorClass: { + const BinaryOperator* B = cast(this); + if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma) + return true; + else + return false; + } + } +} + +//===----------------------------------------------------------------------===// +// Constructors +//===----------------------------------------------------------------------===// + +AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, + unsigned numoutputs, unsigned numinputs, + std::string *names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc) + : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) + , IsSimple(issimple), IsVolatile(isvolatile) + , NumOutputs(numoutputs), NumInputs(numinputs) { + for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) { + Names.push_back(names[i]); + Exprs.push_back(exprs[i]); + Constraints.push_back(constraints[i]); + } + + for (unsigned i = 0; i != numclobbers; i++) + Clobbers.push_back(clobbers[i]); +} + +ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, + Stmt *Body, SourceLocation FCL, + SourceLocation RPL) +: Stmt(ObjCForCollectionStmtClass) { + SubExprs[ELEM] = Elem; + SubExprs[COLLECTION] = reinterpret_cast(Collect); + SubExprs[BODY] = Body; + ForLoc = FCL; + RParenLoc = RPL; +} + + +ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, + SourceLocation rparenloc, + Stmt *catchVarStmtDecl, Stmt *atCatchStmt, + Stmt *atCatchList) +: Stmt(ObjCAtCatchStmtClass) { + SubExprs[SELECTOR] = catchVarStmtDecl; + SubExprs[BODY] = atCatchStmt; + if (!atCatchList) + SubExprs[NEXT_CATCH] = NULL; + else { + ObjCAtCatchStmt *AtCatchList = static_cast(atCatchList); + + while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) + AtCatchList = NextCatch; + + AtCatchList->SubExprs[NEXT_CATCH] = this; + } + AtCatchLoc = atCatchLoc; + RParenLoc = rparenloc; +} + + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +// DeclStmt +Stmt::child_iterator DeclStmt::child_begin() { return getDecl(); } +Stmt::child_iterator DeclStmt::child_end() { return child_iterator(); } + +// NullStmt +Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator NullStmt::child_end() { return child_iterator(); } + +// CompoundStmt +Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; } +Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); } + +// CaseStmt +Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; } + +// DefaultStmt +Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; } +Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; } + +// LabelStmt +Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } +Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } + +// IfStmt +Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// SwitchStmt +Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// WhileStmt +Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// DoStmt +Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// ForStmt +Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// ObjCForCollectionStmt +Stmt::child_iterator ObjCForCollectionStmt::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ObjCForCollectionStmt::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// GotoStmt +Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } + +// IndirectGotoStmt +Stmt::child_iterator IndirectGotoStmt::child_begin() { + return reinterpret_cast(&Target); +} + +Stmt::child_iterator IndirectGotoStmt::child_end() { return ++child_begin(); } + +// ContinueStmt +Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); } + +// BreakStmt +Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); } + +// ReturnStmt +Stmt::child_iterator ReturnStmt::child_begin() { + if (RetExpr) return reinterpret_cast(&RetExpr); + else return child_iterator(); +} + +Stmt::child_iterator ReturnStmt::child_end() { + if (RetExpr) return reinterpret_cast(&RetExpr)+1; + else return child_iterator(); +} + +// AsmStmt +Stmt::child_iterator AsmStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator AsmStmt::child_end() { return child_iterator(); } + +// ObjCAtCatchStmt +Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator ObjCAtCatchStmt::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// 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; +} + +// ObjCAtThrowStmt +Stmt::child_iterator ObjCAtThrowStmt::child_begin() { + return &Throw; +} + +Stmt::child_iterator ObjCAtThrowStmt::child_end() { + return &Throw+1; +} + +// ObjCAtSynchronizedStmt +Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() { + return &SubStmts[0]; +} + +Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() { + return &SubStmts[0]+END_EXPR; +} + diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp new file mode 100644 index 00000000000..d813899b530 --- /dev/null +++ b/clang/lib/AST/StmtDumper.cpp @@ -0,0 +1,486 @@ +//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::dump/Stmt::print methods, which dump out the +// AST in a form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/Compiler.h" +#include +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtDumper Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor { + SourceManager *SM; + FILE *F; + unsigned IndentLevel; + + /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump + /// the first few levels of an AST. This keeps track of how many ast levels + /// are left. + unsigned MaxDepth; + + /// LastLocFilename/LastLocLine - Keep track of the last location we print + /// out so that we can print out deltas from then on out. + const char *LastLocFilename; + unsigned LastLocLine; + public: + StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth) + : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) { + LastLocFilename = ""; + LastLocLine = ~0U; + } + + void DumpSubTree(Stmt *S) { + // Prune the recursion if not using dump all. + if (MaxDepth == 0) return; + + ++IndentLevel; + if (S) { + if (DeclStmt* DS = dyn_cast(S)) + VisitDeclStmt(DS); + else { + Visit(S); + + // Print out children. + Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); + if (CI != CE) { + while (CI != CE) { + fprintf(F, "\n"); + DumpSubTree(*CI++); + } + } + fprintf(F, ")"); + } + } else { + Indent(); + fprintf(F, "<<>>"); + } + --IndentLevel; + } + + void DumpDeclarator(Decl *D); + + void Indent() const { + for (int i = 0, e = IndentLevel; i < e; ++i) + fprintf(F, " "); + } + + void DumpType(QualType T) { + fprintf(F, "'%s'", T.getAsString().c_str()); + + // If the type is directly a typedef, strip off typedefness to give at + // least one level of concreteness. + if (TypedefType *TDT = dyn_cast(T)) + fprintf(F, ":'%s'", TDT->LookThroughTypedefs().getAsString().c_str()); + } + void DumpStmt(const Stmt *Node) { + Indent(); + fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node); + DumpSourceRange(Node); + } + void DumpExpr(const Expr *Node) { + DumpStmt(Node); + fprintf(F, " "); + DumpType(Node->getType()); + } + void DumpSourceRange(const Stmt *Node); + void DumpLocation(SourceLocation Loc); + + // Stmts. + void VisitStmt(Stmt *Node); + void VisitDeclStmt(DeclStmt *Node); + void VisitLabelStmt(LabelStmt *Node); + void VisitGotoStmt(GotoStmt *Node); + + // Exprs + void VisitExpr(Expr *Node); + void VisitDeclRefExpr(DeclRefExpr *Node); + void VisitPreDefinedExpr(PreDefinedExpr *Node); + void VisitCharacterLiteral(CharacterLiteral *Node); + void VisitIntegerLiteral(IntegerLiteral *Node); + void VisitFloatingLiteral(FloatingLiteral *Node); + void VisitStringLiteral(StringLiteral *Str); + void VisitUnaryOperator(UnaryOperator *Node); + void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node); + void VisitMemberExpr(MemberExpr *Node); + void VisitOCUVectorElementExpr(OCUVectorElementExpr *Node); + void VisitBinaryOperator(BinaryOperator *Node); + void VisitCompoundAssignOperator(CompoundAssignOperator *Node); + void VisitAddrLabelExpr(AddrLabelExpr *Node); + void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); + + // C++ + void VisitCXXCastExpr(CXXCastExpr *Node); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); + + // ObjC + void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(ObjCMessageExpr* Node); + void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); + }; +} + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +void StmtDumper::DumpLocation(SourceLocation Loc) { + SourceLocation PhysLoc = SM->getPhysicalLoc(Loc); + + // The general format we print out is filename:line:col, but we drop pieces + // that haven't changed since the last loc printed. + const char *Filename = SM->getSourceName(PhysLoc); + unsigned LineNo = SM->getLineNumber(PhysLoc); + if (strcmp(Filename, LastLocFilename) != 0) { + fprintf(stderr, "%s:%u:%u", Filename, LineNo, SM->getColumnNumber(PhysLoc)); + LastLocFilename = Filename; + LastLocLine = LineNo; + } else if (LineNo != LastLocLine) { + fprintf(stderr, "line:%u:%u", LineNo, SM->getColumnNumber(PhysLoc)); + LastLocLine = LineNo; + } else { + fprintf(stderr, "col:%u", SM->getColumnNumber(PhysLoc)); + } +} + +void StmtDumper::DumpSourceRange(const Stmt *Node) { + // Can't translate locations if a SourceManager isn't available. + if (SM == 0) return; + + // TODO: If the parent expression is available, we can print a delta vs its + // location. + SourceRange R = Node->getSourceRange(); + + fprintf(stderr, " <"); + DumpLocation(R.getBegin()); + if (R.getBegin() != R.getEnd()) { + fprintf(stderr, ", "); + DumpLocation(R.getEnd()); + } + fprintf(stderr, ">"); + + // + +} + + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitStmt(Stmt *Node) { + DumpStmt(Node); +} + +void StmtDumper::DumpDeclarator(Decl *D) { + // FIXME: Need to complete/beautify this... this code simply shows the + // nodes are where they need to be. + if (TypedefDecl *localType = dyn_cast(D)) { + fprintf(F, "\"typedef %s %s\"", + localType->getUnderlyingType().getAsString().c_str(), + localType->getName()); + } else if (ValueDecl *VD = dyn_cast(D)) { + fprintf(F, "\""); + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast(VD)) { + switch (V->getStorageClass()) { + default: assert(0 && "Unknown storage class!"); + case VarDecl::None: break; + case VarDecl::Extern: fprintf(F, "extern "); break; + case VarDecl::Static: fprintf(F, "static "); break; + case VarDecl::Auto: fprintf(F, "auto "); break; + case VarDecl::Register: fprintf(F, "register "); break; + } + } + + std::string Name = VD->getName(); + VD->getType().getAsStringInternal(Name); + fprintf(F, "%s", Name.c_str()); + + // If this is a vardecl with an initializer, emit it. + if (VarDecl *V = dyn_cast(VD)) { + if (V->getInit()) { + fprintf(F, " =\n"); + DumpSubTree(V->getInit()); + } + } + fprintf(F, "\""); + } else if (TagDecl *TD = dyn_cast(D)) { + // print a free standing tag decl (e.g. "struct x;"). + const char *tagname; + if (const IdentifierInfo *II = TD->getIdentifier()) + tagname = II->getName(); + else + tagname = ""; + fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); + // FIXME: print tag bodies. + } else { + assert(0 && "Unexpected decl"); + } +} + +void StmtDumper::VisitDeclStmt(DeclStmt *Node) { + DumpStmt(Node); + fprintf(F,"\n"); + for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { + ++IndentLevel; + Indent(); + fprintf(F, "%p ", (void*) D); + DumpDeclarator(D); + if (D->getNextDeclarator()) + fprintf(F,"\n"); + --IndentLevel; + } +} + +void StmtDumper::VisitLabelStmt(LabelStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s'\n", Node->getName()); +} + +void StmtDumper::VisitGotoStmt(GotoStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel()); +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitExpr(Expr *Node) { + DumpExpr(Node); +} + +void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + switch (Node->getDecl()->getKind()) { + case Decl::Function: fprintf(F,"FunctionDecl"); break; + case Decl::BlockVar: fprintf(F,"BlockVar"); break; + case Decl::FileVar: fprintf(F,"FileVar"); break; + case Decl::ParmVar: fprintf(F,"ParmVar"); break; + case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; + case Decl::Typedef: fprintf(F,"Typedef"); break; + case Decl::Struct: fprintf(F,"Struct"); break; + case Decl::Union: fprintf(F,"Union"); break; + case Decl::Class: fprintf(F,"Class"); break; + case Decl::Enum: fprintf(F,"Enum"); break; + case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; + case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; + default: fprintf(F,"Decl"); break; + } + + fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl()); +} + +void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + DumpExpr(Node->getBase()); + + fprintf(F, " ObjCIvarRefExpr"); + fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl()); +} + +void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) { + DumpExpr(Node); + switch (Node->getIdentType()) { + default: + assert(0 && "unknown case"); + case PreDefinedExpr::Func: + fprintf(F, " __func__"); + break; + case PreDefinedExpr::Function: + fprintf(F, " __FUNCTION__"); + break; + case PreDefinedExpr::PrettyFunction: + fprintf(F, " __PRETTY_FUNCTION__"); + break; + } +} + +void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { + DumpExpr(Node); + fprintf(F, " %d", Node->getValue()); +} + +void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { + DumpExpr(Node); + + bool isSigned = Node->getType()->isSignedIntegerType(); + fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str()); +} +void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { + DumpExpr(Node); + fprintf(F, " %f", Node->getValueAsDouble()); +} + +void StmtDumper::VisitStringLiteral(StringLiteral *Str) { + DumpExpr(Str); + // FIXME: this doesn't print wstrings right. + fprintf(F, " %s\"", Str->isWide() ? "L" : ""); + + for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { + switch (char C = Str->getStrData()[i]) { + default: + if (isprint(C)) + fputc(C, F); + else + fprintf(F, "\\%03o", C); + break; + // Handle some common ones to make dumps prettier. + case '\\': fprintf(F, "\\\\"); break; + case '"': fprintf(F, "\\\""); break; + case '\n': fprintf(F, "\\n"); break; + case '\t': fprintf(F, "\\t"); break; + case '\a': fprintf(F, "\\a"); break; + case '\b': fprintf(F, "\\b"); break; + } + } + fprintf(F, "\""); +} + +void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { + DumpExpr(Node); + fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix", + UnaryOperator::getOpcodeStr(Node->getOpcode())); +} +void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof"); + DumpType(Node->getArgumentType()); +} + +void StmtDumper::VisitMemberExpr(MemberExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", + Node->getMemberDecl()->getName(), (void*)Node->getMemberDecl()); +} +void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", Node->getAccessor().getName()); +} +void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { + DumpExpr(Node); + fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode())); +} +void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { + DumpExpr(Node); + fprintf(F, " '%s' ComputeTy=", + BinaryOperator::getOpcodeStr(Node->getOpcode())); + DumpType(Node->getComputationType()); +} + +// GNU extensions. + +void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel()); +} + +void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { + DumpExpr(Node); + fprintf(F, " "); + DumpType(Node->getArgType1()); + fprintf(F, " "); + DumpType(Node->getArgType2()); +} + +//===----------------------------------------------------------------------===// +// C++ Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", CXXCastExpr::getOpcodeStr(Node->getOpcode())); +} + +void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", Node->getValue() ? "true" : "false"); +} + +//===----------------------------------------------------------------------===// +// Obj-C Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { + DumpExpr(Node); + fprintf(F, " selector=%s", Node->getSelector().getName().c_str()); +} + +void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + DumpType(Node->getEncodedType()); +} + +void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + Selector &selector = Node->getSelector(); + fprintf(F, "%s", selector.getName().c_str()); +} + +void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + fprintf(F, "%s", Node->getProtocol()->getName()); +} +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +/// dump - This does a local dump of the specified AST fragment. It dumps the +/// specified node and a few nodes underneath it, but not the whole subtree. +/// This is useful in a debugger. +void Stmt::dump(SourceManager &SM) const { + StmtDumper P(&SM, stderr, 4); + P.DumpSubTree(const_cast(this)); + fprintf(stderr, "\n"); +} + +/// dump - This does a local dump of the specified AST fragment. It dumps the +/// specified node and a few nodes underneath it, but not the whole subtree. +/// This is useful in a debugger. +void Stmt::dump() const { + StmtDumper P(0, stderr, 4); + P.DumpSubTree(const_cast(this)); + fprintf(stderr, "\n"); +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll(SourceManager &SM) const { + StmtDumper P(&SM, stderr, ~0U); + P.DumpSubTree(const_cast(this)); + fprintf(stderr, "\n"); +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll() const { + StmtDumper P(0, stderr, ~0U); + P.DumpSubTree(const_cast(this)); + fprintf(stderr, "\n"); +} diff --git a/clang/lib/AST/StmtIterator.cpp b/clang/lib/AST/StmtIterator.cpp new file mode 100644 index 00000000000..14083e30a99 --- /dev/null +++ b/clang/lib/AST/StmtIterator.cpp @@ -0,0 +1,118 @@ +//===--- StmtIterator.cpp - Iterators for Statements ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines internal methods for StmtIterator. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtIterator.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" + +using namespace clang; + +static inline VariableArrayType* FindVA(Type* t) { + while (ArrayType* vt = dyn_cast(t)) { + if (VariableArrayType* vat = dyn_cast(vt)) + if (vat->getSizeExpr()) + return vat; + + t = vt->getElementType().getTypePtr(); + } + + return NULL; +} + +void StmtIteratorBase::NextVA() { + assert (getVAPtr()); + + VariableArrayType* p = getVAPtr(); + p = FindVA(p->getElementType().getTypePtr()); + setVAPtr(p); + + if (!p && decl) { + if (VarDecl* VD = dyn_cast(decl)) + if (VD->Init) + return; + + NextDecl(); + } + else { + RawVAPtr = 0; + } +} + +void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { + assert (inDecl()); + assert (getVAPtr() == NULL); + assert (decl); + + if (ImmediateAdvance) { + decl = decl->getNextDeclarator(); + + if (!decl) { + RawVAPtr = 0; + return; + } + } + + for ( ; decl ; decl = decl->getNextDeclarator()) { + if (VarDecl* VD = dyn_cast(decl)) { + if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { + setVAPtr(VAPtr); + return; + } + + if (VD->getInit()) + return; + } + else if (TypedefDecl* TD = dyn_cast(decl)) { + if (VariableArrayType* VAPtr = + FindVA(TD->getUnderlyingType().getTypePtr())) { + setVAPtr(VAPtr); + return; + } + } + else if (EnumConstantDecl* ECD = dyn_cast(decl)) + if (ECD->getInitExpr()) + return; + } + + if (!decl) { + RawVAPtr = 0; + return; + } +} + +StmtIteratorBase::StmtIteratorBase(ScopedDecl* d) + : decl(d), RawVAPtr(DeclMode) { + assert (decl); + NextDecl(false); +} + +StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) +: decl(NULL), RawVAPtr(SizeOfTypeVAMode) { + RawVAPtr |= reinterpret_cast(t); +} + + +Stmt*& StmtIteratorBase::GetDeclExpr() const { + if (VariableArrayType* VAPtr = getVAPtr()) { + assert (VAPtr->SizeExpr); + return reinterpret_cast(VAPtr->SizeExpr); + } + + if (VarDecl* VD = dyn_cast(decl)) { + assert (VD->Init); + return reinterpret_cast(VD->Init); + } + + EnumConstantDecl* ECD = cast(decl); + return reinterpret_cast(ECD->Init); +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp new file mode 100644 index 00000000000..ba82b7fcff7 --- /dev/null +++ b/clang/lib/AST/StmtPrinter.cpp @@ -0,0 +1,854 @@ +//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which +// pretty print the AST back out to C code. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" +#include +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtPrinter Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor { + std::ostream &OS; + unsigned IndentLevel; + clang::PrinterHelper* Helper; + public: + StmtPrinter(std::ostream &os, PrinterHelper* helper) : + OS(os), IndentLevel(0), Helper(helper) {} + + void PrintStmt(Stmt *S, int SubIndent = 1) { + IndentLevel += SubIndent; + if (S && isa(S)) { + // If this is an expr used in a stmt context, indent and newline it. + Indent(); + Visit(S); + OS << ";\n"; + } else if (S) { + Visit(S); + } else { + Indent() << "<<>>\n"; + } + IndentLevel -= SubIndent; + } + + void PrintRawCompoundStmt(CompoundStmt *S); + void PrintRawDecl(Decl *D); + void PrintRawIfStmt(IfStmt *If); + + void PrintExpr(Expr *E) { + if (E) + Visit(E); + else + OS << ""; + } + + std::ostream &Indent(int Delta = 0) const { + for (int i = 0, e = IndentLevel+Delta; i < e; ++i) + OS << " "; + return OS; + } + + bool PrintOffsetOfDesignator(Expr *E); + void VisitUnaryOffsetOf(UnaryOperator *Node); + + void Visit(Stmt* S) { + if (Helper && Helper->handledStmt(S,OS)) + return; + else StmtVisitor::Visit(S); + } + + void VisitStmt(Stmt *Node); +#define STMT(N, CLASS, PARENT) \ + void Visit##CLASS(CLASS *Node); +#include "clang/AST/StmtNodes.def" + }; +} + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitStmt(Stmt *Node) { + Indent() << "<>\n"; +} + +/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and +/// with no newline after the }. +void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { + OS << "{\n"; + for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); + I != E; ++I) + PrintStmt(*I); + + Indent() << "}"; +} + +void StmtPrinter::PrintRawDecl(Decl *D) { + // FIXME: Need to complete/beautify this... this code simply shows the + // nodes are where they need to be. + if (TypedefDecl *localType = dyn_cast(D)) { + OS << "typedef " << localType->getUnderlyingType().getAsString(); + OS << " " << localType->getName(); + } else if (ValueDecl *VD = dyn_cast(D)) { + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast(VD)) { + switch (V->getStorageClass()) { + default: assert(0 && "Unknown storage class!"); + case VarDecl::None: break; + case VarDecl::Extern: OS << "extern "; break; + case VarDecl::Static: OS << "static "; break; + case VarDecl::Auto: OS << "auto "; break; + case VarDecl::Register: OS << "register "; break; + } + } + + std::string Name = VD->getName(); + VD->getType().getAsStringInternal(Name); + OS << Name; + + // If this is a vardecl with an initializer, emit it. + if (VarDecl *V = dyn_cast(VD)) { + if (V->getInit()) { + OS << " = "; + PrintExpr(V->getInit()); + } + } + } else if (TagDecl *TD = dyn_cast(D)) { + // print a free standing tag decl (e.g. "struct x;"). + OS << TD->getKindName(); + OS << " "; + if (const IdentifierInfo *II = TD->getIdentifier()) + OS << II->getName(); + else + OS << ""; + // FIXME: print tag bodies. + } else { + assert(0 && "Unexpected decl"); + } +} + + +void StmtPrinter::VisitNullStmt(NullStmt *Node) { + Indent() << ";\n"; +} + +void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { + for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { + Indent(); + PrintRawDecl(D); + OS << ";\n"; + } +} + +void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) { + Indent(); + PrintRawCompoundStmt(Node); + OS << "\n"; +} + +void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { + Indent(-1) << "case "; + PrintExpr(Node->getLHS()); + if (Node->getRHS()) { + OS << " ... "; + PrintExpr(Node->getRHS()); + } + OS << ":\n"; + + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) { + Indent(-1) << "default:\n"; + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { + Indent(-1) << Node->getName() << ":\n"; + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::PrintRawIfStmt(IfStmt *If) { + OS << "if "; + PrintExpr(If->getCond()); + + if (CompoundStmt *CS = dyn_cast(If->getThen())) { + OS << ' '; + PrintRawCompoundStmt(CS); + OS << (If->getElse() ? ' ' : '\n'); + } else { + OS << '\n'; + PrintStmt(If->getThen()); + if (If->getElse()) Indent(); + } + + if (Stmt *Else = If->getElse()) { + OS << "else"; + + if (CompoundStmt *CS = dyn_cast(Else)) { + OS << ' '; + PrintRawCompoundStmt(CS); + OS << '\n'; + } else if (IfStmt *ElseIf = dyn_cast(Else)) { + OS << ' '; + PrintRawIfStmt(ElseIf); + } else { + OS << '\n'; + PrintStmt(If->getElse()); + } + } +} + +void StmtPrinter::VisitIfStmt(IfStmt *If) { + Indent(); + PrintRawIfStmt(If); +} + +void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { + Indent() << "switch ("; + PrintExpr(Node->getCond()); + OS << ")"; + + // Pretty print compoundstmt bodies (very common). + if (CompoundStmt *CS = dyn_cast(Node->getBody())) { + OS << " "; + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitSwitchCase(SwitchCase*) { + assert(0 && "SwitchCase is an abstract class"); +} + +void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { + Indent() << "while ("; + PrintExpr(Node->getCond()); + OS << ")\n"; + PrintStmt(Node->getBody()); +} + +void StmtPrinter::VisitDoStmt(DoStmt *Node) { + Indent() << "do "; + if (CompoundStmt *CS = dyn_cast(Node->getBody())) { + PrintRawCompoundStmt(CS); + OS << " "; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + Indent(); + } + + OS << "while "; + PrintExpr(Node->getCond()); + OS << ";\n"; +} + +void StmtPrinter::VisitForStmt(ForStmt *Node) { + Indent() << "for ("; + if (Node->getInit()) { + if (DeclStmt *DS = dyn_cast(Node->getInit())) + PrintRawDecl(DS->getDecl()); + else + PrintExpr(cast(Node->getInit())); + } + OS << ";"; + if (Node->getCond()) { + OS << " "; + PrintExpr(Node->getCond()); + } + OS << ";"; + if (Node->getInc()) { + OS << " "; + PrintExpr(Node->getInc()); + } + OS << ") "; + + if (CompoundStmt *CS = dyn_cast(Node->getBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { + Indent() << "for ("; + if (DeclStmt *DS = dyn_cast(Node->getElement())) + PrintRawDecl(DS->getDecl()); + else + PrintExpr(cast(Node->getElement())); + OS << " in "; + PrintExpr(Node->getCollection()); + OS << ") "; + + if (CompoundStmt *CS = dyn_cast(Node->getBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { + Indent() << "goto " << Node->getLabel()->getName() << ";\n"; +} + +void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) { + Indent() << "goto *"; + PrintExpr(Node->getTarget()); + OS << ";\n"; +} + +void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) { + Indent() << "continue;\n"; +} + +void StmtPrinter::VisitBreakStmt(BreakStmt *Node) { + Indent() << "break;\n"; +} + + +void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { + Indent() << "return"; + if (Node->getRetValue()) { + OS << " "; + PrintExpr(Node->getRetValue()); + } + OS << ";\n"; +} + + +void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { + Indent() << "asm "; + + if (Node->isVolatile()) + OS << "volatile "; + + OS << "("; + VisitStringLiteral(Node->getAsmString()); + + // Outputs + if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || + Node->getNumClobbers() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { + if (i != 0) + OS << ", "; + + if (!Node->getOutputName(i).empty()) { + OS << '['; + OS << Node->getOutputName(i); + OS << "] "; + } + + VisitStringLiteral(Node->getOutputConstraint(i)); + OS << " "; + Visit(Node->getOutputExpr(i)); + } + + // Inputs + if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { + if (i != 0) + OS << ", "; + + if (!Node->getInputName(i).empty()) { + OS << '['; + OS << Node->getInputName(i); + OS << "] "; + } + + VisitStringLiteral(Node->getInputConstraint(i)); + OS << " "; + Visit(Node->getInputExpr(i)); + } + + // Clobbers + if (Node->getNumClobbers() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { + if (i != 0) + OS << ", "; + + VisitStringLiteral(Node->getClobber(i)); + } + + OS << ");\n"; +} + +void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { + Indent() << "@try"; + if (CompoundStmt *TS = dyn_cast(Node->getTryBody())) { + PrintRawCompoundStmt(TS); + OS << "\n"; + } + + for (ObjCAtCatchStmt *catchStmt = + static_cast(Node->getCatchStmts()); + catchStmt; + catchStmt = + static_cast(catchStmt->getNextCatchStmt())) { + Indent() << "@catch("; + if (catchStmt->getCatchParamStmt()) { + if (DeclStmt *DS = dyn_cast(catchStmt->getCatchParamStmt())) + PrintRawDecl(DS->getDecl()); + } + OS << ")"; + if (CompoundStmt *CS = dyn_cast(catchStmt->getCatchBody())) + { + PrintRawCompoundStmt(CS); + OS << "\n"; + } + } + + if (ObjCAtFinallyStmt *FS =static_cast( + Node->getFinallyStmt())) { + Indent() << "@finally"; + PrintRawCompoundStmt(dyn_cast(FS->getFinallyBody())); + OS << "\n"; + } +} + +void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) { +} + +void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) { + Indent() << "@catch (...) { /* todo */ } \n"; +} + +void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) { + Indent() << "@throw"; + if (Node->getThrowExpr()) { + OS << " "; + PrintExpr(Node->getThrowExpr()); + } + OS << ";\n"; +} + +void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) { + Indent() << "@synchronized ("; + PrintExpr(Node->getSynchExpr()); + OS << ")"; + PrintRawCompoundStmt(Node->getSynchBody()); + OS << "\n"; +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitExpr(Expr *Node) { + OS << "<>"; +} + +void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + OS << Node->getDecl()->getName(); +} + +void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } + OS << Node->getDecl()->getName(); +} + +void StmtPrinter::VisitPreDefinedExpr(PreDefinedExpr *Node) { + switch (Node->getIdentType()) { + default: + assert(0 && "unknown case"); + case PreDefinedExpr::Func: + OS << "__func__"; + break; + case PreDefinedExpr::Function: + OS << "__FUNCTION__"; + break; + case PreDefinedExpr::PrettyFunction: + OS << "__PRETTY_FUNCTION__"; + break; + } +} + +void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { + // FIXME should print an L for wchar_t constants + unsigned value = Node->getValue(); + switch (value) { + case '\\': + OS << "'\\\\'"; + break; + case '\'': + OS << "'\\''"; + break; + case '\a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + OS << "'\\a'"; + break; + case '\b': + OS << "'\\b'"; + break; + // Nonstandard escape sequence. + /*case '\e': + OS << "'\\e'"; + break;*/ + case '\f': + OS << "'\\f'"; + break; + case '\n': + OS << "'\\n'"; + break; + case '\r': + OS << "'\\r'"; + break; + case '\t': + OS << "'\\t'"; + break; + case '\v': + OS << "'\\v'"; + break; + default: + if (value < 256 && isprint(value)) { + OS << "'" << (char)value << "'"; + } else if (value < 256) { + OS << "'\\x" << std::hex << value << std::dec << "'"; + } else { + // FIXME what to really do here? + OS << value; + } + } +} + +void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { + bool isSigned = Node->getType()->isSignedIntegerType(); + OS << Node->getValue().toString(10, isSigned); + + // Emit suffixes. Integer literals are always a builtin integer type. + switch (cast(Node->getType().getCanonicalType())->getKind()) { + default: assert(0 && "Unexpected type for integer literal!"); + case BuiltinType::Int: break; // no suffix. + case BuiltinType::UInt: OS << 'U'; break; + case BuiltinType::Long: OS << 'L'; break; + case BuiltinType::ULong: OS << "UL"; break; + case BuiltinType::LongLong: OS << "LL"; break; + case BuiltinType::ULongLong: OS << "ULL"; break; + } +} +void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + // FIXME: print value more precisely. + OS << Node->getValueAsDouble(); +} + +void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { + PrintExpr(Node->getSubExpr()); + OS << "i"; +} + +void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { + if (Str->isWide()) OS << 'L'; + OS << '"'; + + // FIXME: this doesn't print wstrings right. + for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { + switch (Str->getStrData()[i]) { + default: OS << Str->getStrData()[i]; break; + // Handle some common ones to make dumps prettier. + case '\\': OS << "\\\\"; break; + case '"': OS << "\\\""; break; + case '\n': OS << "\\n"; break; + case '\t': OS << "\\t"; break; + case '\a': OS << "\\a"; break; + case '\b': OS << "\\b"; break; + } + } + OS << '"'; +} +void StmtPrinter::VisitParenExpr(ParenExpr *Node) { + OS << "("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} +void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { + if (!Node->isPostfix()) { + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); + + // Print a space if this is an "identifier operator" like sizeof or __real. + switch (Node->getOpcode()) { + default: break; + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + case UnaryOperator::Real: + case UnaryOperator::Imag: + case UnaryOperator::Extension: + OS << ' '; + break; + } + } + PrintExpr(Node->getSubExpr()); + + if (Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); +} + +bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { + if (isa(E)) { + // Base case, print the type and comma. + OS << E->getType().getAsString() << ", "; + return true; + } else if (ArraySubscriptExpr *ASE = dyn_cast(E)) { + PrintOffsetOfDesignator(ASE->getLHS()); + OS << "["; + PrintExpr(ASE->getRHS()); + OS << "]"; + return false; + } else { + MemberExpr *ME = cast(E); + bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); + OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getName(); + return false; + } +} + +void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { + OS << "__builtin_offsetof("; + PrintOffsetOfDesignator(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { + OS << (Node->isSizeOf() ? "sizeof(" : "__alignof("); + OS << Node->getArgumentType().getAsString() << ")"; +} +void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { + PrintExpr(Node->getLHS()); + OS << "["; + PrintExpr(Node->getRHS()); + OS << "]"; +} + +void StmtPrinter::VisitCallExpr(CallExpr *Call) { + PrintExpr(Call->getCallee()); + OS << "("; + for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Call->getArg(i)); + } + OS << ")"; +} +void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + + FieldDecl *Field = Node->getMemberDecl(); + assert(Field && "MemberExpr should alway reference a field!"); + OS << Field->getName(); +} +void StmtPrinter::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { + PrintExpr(Node->getBase()); + OS << "."; + OS << Node->getAccessor().getName(); +} +void StmtPrinter::VisitCastExpr(CastExpr *Node) { + OS << "(" << Node->getType().getAsString() << ")"; + PrintExpr(Node->getSubExpr()); +} +void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { + OS << "(" << Node->getType().getAsString() << ")"; + PrintExpr(Node->getInitializer()); +} +void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) { + // No need to print anything, simply forward to the sub expression. + PrintExpr(Node->getSubExpr()); +} +void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { + PrintExpr(Node->getLHS()); + OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; + PrintExpr(Node->getRHS()); +} +void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { + PrintExpr(Node->getLHS()); + OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; + PrintExpr(Node->getRHS()); +} +void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { + PrintExpr(Node->getCond()); + + if (Node->getLHS()) { + OS << " ? "; + PrintExpr(Node->getLHS()); + OS << " : "; + } + else { // Handle GCC extention where LHS can be NULL. + OS << " ?: "; + } + + PrintExpr(Node->getRHS()); +} + +// GNU extensions. + +void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { + OS << "&&" << Node->getLabel()->getName(); +} + +void StmtPrinter::VisitStmtExpr(StmtExpr *E) { + OS << "("; + PrintRawCompoundStmt(E->getSubStmt()); + OS << ")"; +} + +void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { + OS << "__builtin_types_compatible_p("; + OS << Node->getArgType1().getAsString() << ","; + OS << Node->getArgType2().getAsString() << ")"; +} + +void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { + OS << "__builtin_choose_expr("; + PrintExpr(Node->getCond()); + OS << ", "; + PrintExpr(Node->getLHS()); + OS << ", "; + PrintExpr(Node->getRHS()); + OS << ")"; +} + +void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) { + OS << "__builtin_overload("; + for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + OS << ")"; +} + +void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { + OS << "{ "; + for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getInit(i)); + } + OS << " }"; +} + +void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { + OS << "va_arg("; + PrintExpr(Node->getSubExpr()); + OS << ", "; + OS << Node->getType().getAsString(); + OS << ")"; +} + +// C++ + +void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) { + OS << CXXCastExpr::getOpcodeStr(Node->getOpcode()) << '<'; + OS << Node->getDestType().getAsString() << ">("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + OS << (Node->getValue() ? "true" : "false"); +} + +void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { + if (Node->getSubExpr() == 0) + OS << "throw"; + else { + OS << "throw "; + PrintExpr(Node->getSubExpr()); + } +} + +// Obj-C + +void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { + OS << "@"; + VisitStringLiteral(Node->getString()); +} + +void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + OS << "@encode(" << Node->getEncodedType().getAsString() << ")"; +} + +void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + OS << "@selector(" << Node->getSelector().getName() << ")"; +} + +void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + OS << "@protocol(" << Node->getProtocol()->getName() << ")"; +} + +void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { + OS << "["; + Expr *receiver = Mess->getReceiver(); + if (receiver) PrintExpr(receiver); + else OS << Mess->getClassName()->getName(); + Selector &selector = Mess->getSelector(); + if (selector.isUnarySelector()) { + OS << " " << selector.getIdentifierInfoForSlot(0)->getName(); + } else { + for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { + if (selector.getIdentifierInfoForSlot(i)) + OS << selector.getIdentifierInfoForSlot(i)->getName() << ":"; + else + OS << ":"; + PrintExpr(Mess->getArg(i)); + } + } + OS << "]"; +} + +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +void Stmt::dumpPretty() const { + printPretty(*llvm::cerr.stream()); +} + +void Stmt::printPretty(std::ostream &OS, PrinterHelper* Helper) const { + if (this == 0) { + OS << ""; + return; + } + + StmtPrinter P(OS, Helper); + P.Visit(const_cast(this)); +} + +//===----------------------------------------------------------------------===// +// PrinterHelper +//===----------------------------------------------------------------------===// + +// Implement virtual destructor. +PrinterHelper::~PrinterHelper() {} diff --git a/clang/lib/AST/StmtSerialization.cpp b/clang/lib/AST/StmtSerialization.cpp new file mode 100644 index 00000000000..433e8e27026 --- /dev/null +++ b/clang/lib/AST/StmtSerialization.cpp @@ -0,0 +1,1001 @@ +//===--- StmtSerialization.cpp - Serialization of Statements --------------===// +// +// 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 type-specific methods for serializing statements +// and expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Expr.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; +using llvm::Serializer; +using llvm::Deserializer; + +void Stmt::Emit(Serializer& S) const { + S.FlushRecord(); + S.EmitInt(getStmtClass()); + EmitImpl(S); + S.FlushRecord(); +} + +Stmt* Stmt::Create(Deserializer& D) { + StmtClass SC = static_cast(D.ReadInt()); + + switch (SC) { + default: + assert (false && "Not implemented."); + return NULL; + + case AddrLabelExprClass: + return AddrLabelExpr::CreateImpl(D); + + case ArraySubscriptExprClass: + return ArraySubscriptExpr::CreateImpl(D); + + case AsmStmtClass: + return AsmStmt::CreateImpl(D); + + case BinaryOperatorClass: + return BinaryOperator::CreateImpl(D); + + case BreakStmtClass: + return BreakStmt::CreateImpl(D); + + case CallExprClass: + return CallExpr::CreateImpl(D); + + case CaseStmtClass: + return CaseStmt::CreateImpl(D); + + case CastExprClass: + return CastExpr::CreateImpl(D); + + case CharacterLiteralClass: + return CharacterLiteral::CreateImpl(D); + + case CompoundAssignOperatorClass: + return CompoundAssignOperator::CreateImpl(D); + + case CompoundLiteralExprClass: + return CompoundLiteralExpr::CreateImpl(D); + + case CompoundStmtClass: + return CompoundStmt::CreateImpl(D); + + case ConditionalOperatorClass: + return ConditionalOperator::CreateImpl(D); + + case ContinueStmtClass: + return ContinueStmt::CreateImpl(D); + + case DeclRefExprClass: + return DeclRefExpr::CreateImpl(D); + + case DeclStmtClass: + return DeclStmt::CreateImpl(D); + + case DefaultStmtClass: + return DefaultStmt::CreateImpl(D); + + case DoStmtClass: + return DoStmt::CreateImpl(D); + + case FloatingLiteralClass: + return FloatingLiteral::CreateImpl(D); + + case ForStmtClass: + return ForStmt::CreateImpl(D); + + case GotoStmtClass: + return GotoStmt::CreateImpl(D); + + case IfStmtClass: + return IfStmt::CreateImpl(D); + + case ImaginaryLiteralClass: + return ImaginaryLiteral::CreateImpl(D); + + case ImplicitCastExprClass: + return ImplicitCastExpr::CreateImpl(D); + + case IndirectGotoStmtClass: + return IndirectGotoStmt::CreateImpl(D); + + case InitListExprClass: + return InitListExpr::CreateImpl(D); + + case IntegerLiteralClass: + return IntegerLiteral::CreateImpl(D); + + case LabelStmtClass: + return LabelStmt::CreateImpl(D); + + case MemberExprClass: + return MemberExpr::CreateImpl(D); + + case NullStmtClass: + return NullStmt::CreateImpl(D); + + case ParenExprClass: + return ParenExpr::CreateImpl(D); + + case PreDefinedExprClass: + return PreDefinedExpr::CreateImpl(D); + + case ReturnStmtClass: + return ReturnStmt::CreateImpl(D); + + case SizeOfAlignOfTypeExprClass: + return SizeOfAlignOfTypeExpr::CreateImpl(D); + + case StmtExprClass: + return StmtExpr::CreateImpl(D); + + case StringLiteralClass: + return StringLiteral::CreateImpl(D); + + case SwitchStmtClass: + return SwitchStmt::CreateImpl(D); + + case UnaryOperatorClass: + return UnaryOperator::CreateImpl(D); + + case WhileStmtClass: + return WhileStmt::CreateImpl(D); + + //==--------------------------------------==// + // Objective C + //==--------------------------------------==// + + case ObjCAtCatchStmtClass: + return ObjCAtCatchStmt::CreateImpl(D); + + case ObjCAtFinallyStmtClass: + return ObjCAtFinallyStmt::CreateImpl(D); + + case ObjCAtSynchronizedStmtClass: + return ObjCAtSynchronizedStmt::CreateImpl(D); + + case ObjCAtThrowStmtClass: + return ObjCAtThrowStmt::CreateImpl(D); + + case ObjCAtTryStmtClass: + return ObjCAtTryStmt::CreateImpl(D); + + case ObjCEncodeExprClass: + return ObjCEncodeExpr::CreateImpl(D); + + case ObjCForCollectionStmtClass: + return ObjCForCollectionStmt::CreateImpl(D); + + case ObjCIvarRefExprClass: + return ObjCIvarRefExpr::CreateImpl(D); + + case ObjCSelectorExprClass: + return ObjCSelectorExpr::CreateImpl(D); + + case ObjCStringLiteralClass: + return ObjCStringLiteral::CreateImpl(D); + } +} + +//===----------------------------------------------------------------------===// +// C Serialization +//===----------------------------------------------------------------------===// + +void AddrLabelExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(AmpAmpLoc); + S.Emit(LabelLoc); + S.EmitPtr(Label); +} + +AddrLabelExpr* AddrLabelExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation AALoc = SourceLocation::ReadVal(D); + SourceLocation LLoc = SourceLocation::ReadVal(D); + AddrLabelExpr* expr = new AddrLabelExpr(AALoc,LLoc,NULL,t); + D.ReadPtr(expr->Label); // Pointer may be backpatched. + return expr; +} + +void ArraySubscriptExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(RBracketLoc); + S.BatchEmitOwnedPtrs(getLHS(),getRHS()); +} + +ArraySubscriptExpr* ArraySubscriptExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + Expr *LHS, *RHS; + D.BatchReadOwnedPtrs(LHS,RHS); + return new ArraySubscriptExpr(LHS,RHS,t,L); +} + +void AsmStmt::EmitImpl(Serializer& S) const { + S.Emit(AsmLoc); + + getAsmString()->EmitImpl(S); + S.Emit(RParenLoc); + + S.EmitBool(IsVolatile); + S.EmitBool(IsSimple); + S.EmitInt(NumOutputs); + S.EmitInt(NumInputs); + + unsigned size = NumOutputs + NumInputs; + + for (unsigned i = 0; i < size; ++i) + S.EmitCStr(Names[i].c_str()); + + for (unsigned i = 0; i < size; ++i) + Constraints[i]->EmitImpl(S); + + for (unsigned i = 0; i < size; ++i) + S.EmitOwnedPtr(Exprs[i]); + + S.EmitInt(Clobbers.size()); + for (unsigned i = 0, e = Clobbers.size(); i != e; ++i) + Clobbers[i]->EmitImpl(S); +} + +AsmStmt* AsmStmt::CreateImpl(Deserializer& D) { + SourceLocation ALoc = SourceLocation::ReadVal(D); + StringLiteral *AsmStr = StringLiteral::CreateImpl(D); + SourceLocation PLoc = SourceLocation::ReadVal(D); + + bool IsVolatile = D.ReadBool(); + bool IsSimple = D.ReadBool(); + AsmStmt *Stmt = new AsmStmt(ALoc, IsSimple, IsVolatile, 0, 0, 0, 0, 0, + AsmStr, + 0, 0, PLoc); + + Stmt->NumOutputs = D.ReadInt(); + Stmt->NumInputs = D.ReadInt(); + + unsigned size = Stmt->NumOutputs + Stmt->NumInputs; + + Stmt->Names.reserve(size); + for (unsigned i = 0; i < size; ++i) { + std::vector data; + D.ReadCStr(data, false); + + Stmt->Names.push_back(std::string(data.begin(), data.end())); + } + + Stmt->Constraints.reserve(size); + for (unsigned i = 0; i < size; ++i) + Stmt->Constraints.push_back(StringLiteral::CreateImpl(D)); + + Stmt->Exprs.reserve(size); + for (unsigned i = 0; i < size; ++i) + Stmt->Exprs.push_back(D.ReadOwnedPtr()); + + unsigned NumClobbers = D.ReadInt(); + Stmt->Clobbers.reserve(NumClobbers); + for (unsigned i = 0; i < NumClobbers; ++i) + Stmt->Clobbers.push_back(StringLiteral::CreateImpl(D)); + + return Stmt; +} + +void BinaryOperator::EmitImpl(Serializer& S) const { + S.EmitInt(Opc); + S.Emit(OpLoc);; + S.Emit(getType()); + S.BatchEmitOwnedPtrs(getLHS(),getRHS()); +} + +BinaryOperator* BinaryOperator::CreateImpl(Deserializer& D) { + Opcode Opc = static_cast(D.ReadInt()); + SourceLocation OpLoc = SourceLocation::ReadVal(D); + QualType Result = QualType::ReadVal(D); + Expr *LHS, *RHS; + D.BatchReadOwnedPtrs(LHS,RHS); + + return new BinaryOperator(LHS,RHS,Opc,Result,OpLoc); +} + +void BreakStmt::EmitImpl(Serializer& S) const { + S.Emit(BreakLoc); +} + +BreakStmt* BreakStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + return new BreakStmt(Loc); +} + +void CallExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(RParenLoc); + S.EmitInt(NumArgs); + S.BatchEmitOwnedPtrs(NumArgs+1,SubExprs); +} + +CallExpr* CallExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + unsigned NumArgs = D.ReadInt(); + Expr** SubExprs = new Expr*[NumArgs+1]; + D.BatchReadOwnedPtrs(NumArgs+1,SubExprs); + + return new CallExpr(SubExprs,NumArgs,t,L); +} + +void CaseStmt::EmitImpl(Serializer& S) const { + S.Emit(CaseLoc); + S.EmitPtr(getNextSwitchCase()); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubExprs[0]); +} + +CaseStmt* CaseStmt::CreateImpl(Deserializer& D) { + SourceLocation CaseLoc = SourceLocation::ReadVal(D); + CaseStmt* stmt = new CaseStmt(NULL,NULL,NULL,CaseLoc); + D.ReadPtr(stmt->NextSwitchCase); + D.BatchReadOwnedPtrs((unsigned) END_EXPR,&stmt->SubExprs[0]); + return stmt; +} + +void CastExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(Loc); + S.EmitOwnedPtr(Op); +} + +CastExpr* CastExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation Loc = SourceLocation::ReadVal(D); + Expr* Op = D.ReadOwnedPtr(); + return new CastExpr(t,Op,Loc); +} + + +void CharacterLiteral::EmitImpl(Serializer& S) const { + S.Emit(Value); + S.Emit(Loc); + S.Emit(getType()); +} + +CharacterLiteral* CharacterLiteral::CreateImpl(Deserializer& D) { + unsigned value = D.ReadInt(); + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + return new CharacterLiteral(value,T,Loc); +} + +void CompoundAssignOperator::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(ComputationType); + S.Emit(getOperatorLoc()); + S.EmitInt(getOpcode()); + S.BatchEmitOwnedPtrs(getLHS(),getRHS()); +} + +CompoundAssignOperator* +CompoundAssignOperator::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + QualType c = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + Opcode Opc = static_cast(D.ReadInt()); + Expr* LHS, *RHS; + D.BatchReadOwnedPtrs(LHS,RHS); + + return new CompoundAssignOperator(LHS,RHS,Opc,t,c,L); +} + +void CompoundLiteralExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(getLParenLoc()); + S.EmitBool(isFileScope()); + S.EmitOwnedPtr(Init); +} + +CompoundLiteralExpr* CompoundLiteralExpr::CreateImpl(Deserializer& D) { + QualType Q = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + bool fileScope = D.ReadBool(); + Expr* Init = D.ReadOwnedPtr(); + return new CompoundLiteralExpr(L, Q, Init, fileScope); +} + +void CompoundStmt::EmitImpl(Serializer& S) const { + S.Emit(LBracLoc); + S.Emit(RBracLoc); + S.Emit(Body.size()); + + for (const_body_iterator I=body_begin(), E=body_end(); I!=E; ++I) + S.EmitOwnedPtr(*I); +} + +CompoundStmt* CompoundStmt::CreateImpl(Deserializer& D) { + SourceLocation LB = SourceLocation::ReadVal(D); + SourceLocation RB = SourceLocation::ReadVal(D); + unsigned size = D.ReadInt(); + + CompoundStmt* stmt = new CompoundStmt(NULL,0,LB,RB); + + stmt->Body.reserve(size); + + for (unsigned i = 0; i < size; ++i) + stmt->Body.push_back(D.ReadOwnedPtr()); + + return stmt; +} + +void ConditionalOperator::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR, SubExprs); +} + +ConditionalOperator* ConditionalOperator::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + ConditionalOperator* c = new ConditionalOperator(NULL,NULL,NULL,t); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, c->SubExprs); + return c; +} + +void ContinueStmt::EmitImpl(Serializer& S) const { + S.Emit(ContinueLoc); +} + +ContinueStmt* ContinueStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + return new ContinueStmt(Loc); +} + +void DeclStmt::EmitImpl(Serializer& S) const { + // FIXME: special handling for struct decls. + S.EmitOwnedPtr(getDecl()); + S.Emit(StartLoc); + S.Emit(EndLoc); +} + +void DeclRefExpr::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + + // Some DeclRefExprs can actually hold the owning reference to a FunctionDecl. + // This occurs when an implicitly defined function is called, and + // the decl does not appear in the source file. We thus check if the + // decl pointer has been registered, and if not, emit an owned pointer. + + // FIXME: While this will work for serialization, it won't work for + // memory management. The only reason this works for serialization is + // because we are tracking all serialized pointers. Either DeclRefExpr + // needs an explicit bit indicating that it owns the the object, + // or we need a different ownership model. + + const Decl* d = getDecl(); + + if (!S.isRegistered(d)) { + assert (isa(d) + && "DeclRefExpr can only own FunctionDecls for implicitly def. funcs."); + + S.EmitBool(true); + S.EmitOwnedPtr(d); + } + else { + S.EmitBool(false); + S.EmitPtr(d); + } +} + +DeclRefExpr* DeclRefExpr::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + bool OwnsDecl = D.ReadBool(); + ValueDecl* decl; + + if (!OwnsDecl) + D.ReadPtr(decl,false); // No backpatching. + else + decl = cast(D.ReadOwnedPtr()); + + return new DeclRefExpr(decl,T,Loc); +} + + +DeclStmt* DeclStmt::CreateImpl(Deserializer& D) { + ScopedDecl* decl = cast(D.ReadOwnedPtr()); + SourceLocation StartLoc = SourceLocation::ReadVal(D); + SourceLocation EndLoc = SourceLocation::ReadVal(D); + return new DeclStmt(decl, StartLoc, EndLoc); +} + +void DefaultStmt::EmitImpl(Serializer& S) const { + S.Emit(DefaultLoc); + S.EmitOwnedPtr(getSubStmt()); + S.EmitPtr(getNextSwitchCase()); +} + +DefaultStmt* DefaultStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + Stmt* SubStmt = D.ReadOwnedPtr(); + + DefaultStmt* stmt = new DefaultStmt(Loc,SubStmt); + stmt->setNextSwitchCase(D.ReadPtr()); + + return stmt; +} + +void DoStmt::EmitImpl(Serializer& S) const { + S.Emit(DoLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getBody()); +} + +DoStmt* DoStmt::CreateImpl(Deserializer& D) { + SourceLocation DoLoc = SourceLocation::ReadVal(D); + Expr* Cond = D.ReadOwnedPtr(); + Stmt* Body = D.ReadOwnedPtr(); + return new DoStmt(Body,Cond,DoLoc); +} + +void FloatingLiteral::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + S.EmitBool(isExact()); + S.Emit(Value); +} + +FloatingLiteral* FloatingLiteral::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType t = QualType::ReadVal(D); + bool isExact = D.ReadBool(); + llvm::APFloat Val = llvm::APFloat::ReadVal(D); + FloatingLiteral* expr = new FloatingLiteral(Val,&isExact,t,Loc); + return expr; +} + +void ForStmt::EmitImpl(Serializer& S) const { + S.Emit(ForLoc); + S.EmitOwnedPtr(getInit()); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getInc()); + S.EmitOwnedPtr(getBody()); +} + +ForStmt* ForStmt::CreateImpl(Deserializer& D) { + SourceLocation ForLoc = SourceLocation::ReadVal(D); + Stmt* Init = D.ReadOwnedPtr(); + Expr* Cond = D.ReadOwnedPtr(); + Expr* Inc = D.ReadOwnedPtr(); + Stmt* Body = D.ReadOwnedPtr(); + return new ForStmt(Init,Cond,Inc,Body,ForLoc); +} + +void GotoStmt::EmitImpl(Serializer& S) const { + S.Emit(GotoLoc); + S.Emit(LabelLoc); + S.EmitPtr(Label); +} + +GotoStmt* GotoStmt::CreateImpl(Deserializer& D) { + SourceLocation GotoLoc = SourceLocation::ReadVal(D); + SourceLocation LabelLoc = SourceLocation::ReadVal(D); + GotoStmt* stmt = new GotoStmt(NULL,GotoLoc,LabelLoc); + D.ReadPtr(stmt->Label); // This pointer may be backpatched later. + return stmt; +} + +void IfStmt::EmitImpl(Serializer& S) const { + S.Emit(IfLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getThen()); + S.EmitOwnedPtr(getElse()); +} + +IfStmt* IfStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + Expr* Cond = D.ReadOwnedPtr(); + Stmt* Then = D.ReadOwnedPtr(); + Stmt* Else = D.ReadOwnedPtr(); + return new IfStmt(L,Cond,Then,Else); +} + +void ImaginaryLiteral::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.EmitOwnedPtr(Val); +} + +ImaginaryLiteral* ImaginaryLiteral::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + Expr* expr = D.ReadOwnedPtr(); + assert (isa(expr) || isa(expr)); + return new ImaginaryLiteral(expr,t); +} + +void ImplicitCastExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.EmitOwnedPtr(Op); +} + +ImplicitCastExpr* ImplicitCastExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + Expr* Op = D.ReadOwnedPtr(); + return new ImplicitCastExpr(t,Op); +} + +void IndirectGotoStmt::EmitImpl(Serializer& S) const { + S.EmitOwnedPtr(Target); +} + +IndirectGotoStmt* IndirectGotoStmt::CreateImpl(Deserializer& D) { + Expr* Target = D.ReadOwnedPtr(); + return new IndirectGotoStmt(Target); +} + +void InitListExpr::EmitImpl(Serializer& S) const { + S.Emit(LBraceLoc); + S.Emit(RBraceLoc); + S.EmitInt(NumInits); + S.BatchEmitOwnedPtrs(NumInits,InitExprs); +} + +InitListExpr* InitListExpr::CreateImpl(Deserializer& D) { + InitListExpr* expr = new InitListExpr(); + expr->LBraceLoc = SourceLocation::ReadVal(D); + expr->RBraceLoc = SourceLocation::ReadVal(D); + expr->NumInits = D.ReadInt(); + assert(expr->NumInits); + expr->InitExprs = new Expr*[expr->NumInits]; + D.BatchReadOwnedPtrs(expr->NumInits,expr->InitExprs); + return expr; +} + +void IntegerLiteral::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + S.Emit(getValue()); +} + +IntegerLiteral* IntegerLiteral::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + + // Create a dummy APInt because it is more efficient to deserialize + // it in place with the deserialized IntegerLiteral. (fewer copies) + llvm::APInt temp; + IntegerLiteral* expr = new IntegerLiteral(temp,T,Loc); + D.Read(expr->Value); + + return expr; +} + +void LabelStmt::EmitImpl(Serializer& S) const { + S.EmitPtr(Label); + S.Emit(IdentLoc); + S.EmitOwnedPtr(SubStmt); +} + +LabelStmt* LabelStmt::CreateImpl(Deserializer& D) { + IdentifierInfo* Label = D.ReadPtr(); + SourceLocation IdentLoc = SourceLocation::ReadVal(D); + Stmt* SubStmt = D.ReadOwnedPtr(); + return new LabelStmt(IdentLoc,Label,SubStmt); +} + +void MemberExpr::EmitImpl(Serializer& S) const { + S.Emit(MemberLoc); + S.EmitPtr(MemberDecl); + S.EmitBool(IsArrow); + S.Emit(getType()); + S.EmitOwnedPtr(Base); +} + +MemberExpr* MemberExpr::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + FieldDecl* MemberDecl = cast(D.ReadPtr()); + bool IsArrow = D.ReadBool(); + QualType T = QualType::ReadVal(D); + Expr* base = D.ReadOwnedPtr(); + + return new MemberExpr(base,IsArrow,MemberDecl,L,T); +} + +void NullStmt::EmitImpl(Serializer& S) const { + S.Emit(SemiLoc); +} + +NullStmt* NullStmt::CreateImpl(Deserializer& D) { + SourceLocation SemiLoc = SourceLocation::ReadVal(D); + return new NullStmt(SemiLoc); +} + +void ParenExpr::EmitImpl(Serializer& S) const { + S.Emit(L); + S.Emit(R); + S.EmitOwnedPtr(Val); +} + +ParenExpr* ParenExpr::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + SourceLocation R = SourceLocation::ReadVal(D); + Expr* val = D.ReadOwnedPtr(); + return new ParenExpr(L,R,val); +} + +void PreDefinedExpr::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.EmitInt(getIdentType()); + S.Emit(getType()); +} + +PreDefinedExpr* PreDefinedExpr::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + IdentType it = static_cast(D.ReadInt()); + QualType Q = QualType::ReadVal(D); + return new PreDefinedExpr(Loc,Q,it); +} + +void ReturnStmt::EmitImpl(Serializer& S) const { + S.Emit(RetLoc); + S.EmitOwnedPtr(RetExpr); +} + +ReturnStmt* ReturnStmt::CreateImpl(Deserializer& D) { + SourceLocation RetLoc = SourceLocation::ReadVal(D); + Expr* RetExpr = D.ReadOwnedPtr(); + return new ReturnStmt(RetLoc,RetExpr); +} + +void SizeOfAlignOfTypeExpr::EmitImpl(Serializer& S) const { + S.EmitBool(isSizeof); + S.Emit(Ty); + S.Emit(getType()); + S.Emit(OpLoc); + S.Emit(RParenLoc); +} + +SizeOfAlignOfTypeExpr* SizeOfAlignOfTypeExpr::CreateImpl(Deserializer& D) { + bool isSizeof = D.ReadBool(); + QualType Ty = QualType::ReadVal(D); + QualType Res = QualType::ReadVal(D); + SourceLocation OpLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + + return new SizeOfAlignOfTypeExpr(isSizeof,Ty,Res,OpLoc,RParenLoc); +} + +void StmtExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(LParenLoc); + S.Emit(RParenLoc); + S.EmitOwnedPtr(SubStmt); +} + +StmtExpr* StmtExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + SourceLocation R = SourceLocation::ReadVal(D); + CompoundStmt* SubStmt = cast(D.ReadOwnedPtr()); + return new StmtExpr(SubStmt,t,L,R); +} + +void StringLiteral::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(firstTokLoc); + S.Emit(lastTokLoc); + S.EmitBool(isWide()); + S.Emit(getByteLength()); + + for (unsigned i = 0 ; i < ByteLength; ++i) + S.EmitInt(StrData[i]); +} + +StringLiteral* StringLiteral::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation firstTokLoc = SourceLocation::ReadVal(D); + SourceLocation lastTokLoc = SourceLocation::ReadVal(D); + bool isWide = D.ReadBool(); + unsigned ByteLength = D.ReadInt(); + + StringLiteral* sl = new StringLiteral(NULL,0,isWide,t,firstTokLoc,lastTokLoc); + + char* StrData = new char[ByteLength]; + for (unsigned i = 0; i < ByteLength; ++i) + StrData[i] = (char) D.ReadInt(); + + sl->ByteLength = ByteLength; + sl->StrData = StrData; + + return sl; +} + +void SwitchStmt::EmitImpl(Serializer& S) const { + S.Emit(SwitchLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getBody()); + S.EmitPtr(FirstCase); +} + +SwitchStmt* SwitchStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + Stmt* Cond = D.ReadOwnedPtr(); + Stmt* Body = D.ReadOwnedPtr(); + SwitchCase* FirstCase = cast(D.ReadPtr()); + + SwitchStmt* stmt = new SwitchStmt(cast(Cond)); + stmt->setBody(Body,Loc); + stmt->FirstCase = FirstCase; + + return stmt; +} + +void UnaryOperator::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(Loc); + S.EmitInt(Opc); + S.EmitOwnedPtr(Val); +} + +UnaryOperator* UnaryOperator::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + Opcode Opc = static_cast(D.ReadInt()); + Expr* Val = D.ReadOwnedPtr(); + return new UnaryOperator(Val,Opc,t,L); +} + +void WhileStmt::EmitImpl(Serializer& S) const { + S.Emit(WhileLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getBody()); +} + +WhileStmt* WhileStmt::CreateImpl(Deserializer& D) { + SourceLocation WhileLoc = SourceLocation::ReadVal(D); + Expr* Cond = D.ReadOwnedPtr(); + Stmt* Body = D.ReadOwnedPtr(); + return new WhileStmt(Cond,Body,WhileLoc); +} + +//===----------------------------------------------------------------------===// +// Objective C Serialization +//===----------------------------------------------------------------------===// + +void ObjCAtCatchStmt::EmitImpl(Serializer& S) const { + S.Emit(AtCatchLoc); + S.Emit(RParenLoc); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubExprs[0]); +} + +ObjCAtCatchStmt* ObjCAtCatchStmt::CreateImpl(Deserializer& D) { + SourceLocation AtCatchLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + + ObjCAtCatchStmt* stmt = new ObjCAtCatchStmt(AtCatchLoc,RParenLoc); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubExprs[0]); + + return stmt; +} + +void ObjCAtFinallyStmt::EmitImpl(Serializer& S) const { + S.Emit(AtFinallyLoc); + S.EmitOwnedPtr(AtFinallyStmt); +} + +ObjCAtFinallyStmt* ObjCAtFinallyStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + Stmt* AtFinallyStmt = D.ReadOwnedPtr(); + return new ObjCAtFinallyStmt(Loc,AtFinallyStmt); +} + +void ObjCAtSynchronizedStmt::EmitImpl(Serializer& S) const { + S.Emit(AtSynchronizedLoc); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubStmts[0]); + } + +ObjCAtSynchronizedStmt* ObjCAtSynchronizedStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + ObjCAtSynchronizedStmt* stmt = new ObjCAtSynchronizedStmt(L,0,0); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]); + return stmt; +} + +void ObjCAtThrowStmt::EmitImpl(Serializer& S) const { + S.Emit(AtThrowLoc); + S.EmitOwnedPtr(Throw); +} + +ObjCAtThrowStmt* ObjCAtThrowStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + Stmt* Throw = D.ReadOwnedPtr(); + return new ObjCAtThrowStmt(L,Throw); +} + +void ObjCAtTryStmt::EmitImpl(Serializer& S) const { + S.Emit(AtTryLoc); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubStmts[0]); +} + +ObjCAtTryStmt* ObjCAtTryStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + ObjCAtTryStmt* stmt = new ObjCAtTryStmt(L,NULL,NULL,NULL); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]); + return stmt; +} + +void ObjCEncodeExpr::EmitImpl(Serializer& S) const { + S.Emit(AtLoc); + S.Emit(RParenLoc); + S.Emit(getType()); + S.Emit(EncType); +} + +ObjCEncodeExpr* ObjCEncodeExpr::CreateImpl(Deserializer& D) { + SourceLocation AtLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + QualType ET = QualType::ReadVal(D); + return new ObjCEncodeExpr(T,ET,AtLoc,RParenLoc); +} + +void ObjCForCollectionStmt::EmitImpl(Serializer& S) const { + S.Emit(ForLoc); + S.Emit(RParenLoc); + S.BatchEmitOwnedPtrs(getElement(),getCollection(),getBody()); +} + +ObjCForCollectionStmt* ObjCForCollectionStmt::CreateImpl(Deserializer& D) { + SourceLocation ForLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + Stmt* Element; + Expr* Collection; + Stmt* Body; + D.BatchReadOwnedPtrs(Element,Collection,Body); + return new ObjCForCollectionStmt(Element,Collection,Body,ForLoc, RParenLoc); +} + +void ObjCIvarRefExpr::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + S.EmitPtr(getDecl()); +} + +ObjCIvarRefExpr* ObjCIvarRefExpr::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + ObjCIvarRefExpr* dr = new ObjCIvarRefExpr(NULL,T,Loc); + D.ReadPtr(dr->D,false); + return dr; +} + +void ObjCSelectorExpr::EmitImpl(Serializer& S) const { + S.Emit(AtLoc); + S.Emit(RParenLoc); + S.Emit(getType()); + S.Emit(SelName); +} + +ObjCSelectorExpr* ObjCSelectorExpr::CreateImpl(Deserializer& D) { + SourceLocation AtLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + Selector SelName = Selector::ReadVal(D); + + return new ObjCSelectorExpr(T,SelName,AtLoc,RParenLoc); +} + +void ObjCStringLiteral::EmitImpl(Serializer& S) const { + S.Emit(AtLoc); + S.Emit(getType()); + S.EmitOwnedPtr(String); +} + +ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + StringLiteral* String = cast(D.ReadOwnedPtr()); + return new ObjCStringLiteral(String,T,L); +} diff --git a/clang/lib/AST/StmtViz.cpp b/clang/lib/AST/StmtViz.cpp new file mode 100644 index 00000000000..51d514b20aa --- /dev/null +++ b/clang/lib/AST/StmtViz.cpp @@ -0,0 +1,59 @@ +//===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Stmt::viewAST, which generates a Graphviz DOT file +// that depicts the AST and then calls Graphviz/dot+gv on it. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtGraphTraits.h" +#include "llvm/Support/GraphWriter.h" +#include + +using namespace clang; + +void Stmt::viewAST() const { +#ifndef NDEBUG + llvm::ViewGraph(this,"AST"); +#else + llvm::cerr << "Stmt::viewAST is only available in debug builds on " + << "systems with Graphviz or gv!\n"; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits : public DefaultDOTGraphTraits { + static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) { + +#ifndef NDEBUG + std::ostringstream Out; + + if (Node) + Out << Node->getStmtClassName(); + else + Out << ""; + + std::string OutStr = Out.str(); + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } + + return OutStr; +#else + return ""; +#endif + } +}; +} // end namespace llvm diff --git a/clang/lib/AST/TranslationUnit.cpp b/clang/lib/AST/TranslationUnit.cpp new file mode 100644 index 00000000000..b91448b2d3f --- /dev/null +++ b/clang/lib/AST/TranslationUnit.cpp @@ -0,0 +1,225 @@ +//===--- TranslationUnit.cpp - Abstraction for Translation Units ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// FIXME: This should eventually be moved out of the driver, or replaced +// with its eventual successor. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TranslationUnit.h" + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/SourceManager.h" +#include "clang/AST/AST.h" + +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/OwningPtr.h" + +#include + +using namespace clang; + +enum { BasicMetadataBlock = 1, + ASTContextBlock = 2, + DeclsBlock = 3 }; + + +bool clang::EmitASTBitcodeFile(const TranslationUnit& TU, + const llvm::sys::Path& Filename) { + + // Reserve 256K for bitstream buffer. + std::vector Buffer; + Buffer.reserve(256*1024); + + // Create bitstream. + llvm::BitstreamWriter Stream(Buffer); + + // Emit the preamble. + Stream.Emit((unsigned)'B', 8); + Stream.Emit((unsigned)'C', 8); + Stream.Emit(0xC, 4); + Stream.Emit(0xF, 4); + Stream.Emit(0xE, 4); + Stream.Emit(0x0, 4); + + { + // Create serializer. Placing it in its own scope assures any necessary + // finalization of bits to the buffer in the serializer's dstor. + llvm::Serializer Sezr(Stream); + + // Emit the translation unit. + TU.Emit(Sezr); + } + + // Write the bits to disk. + if (FILE* fp = fopen(Filename.c_str(),"wb")) { + fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp); + fclose(fp); + return true; + } + + return false; +} + +void TranslationUnit::Emit(llvm::Serializer& Sezr) const { + + // ===---------------------------------------------------===/ + // Serialize the top-level decls. + // ===---------------------------------------------------===/ + + Sezr.EnterBlock(DeclsBlock); + + // Only serialize the head of a decl chain. The ASTConsumer interfaces + // provides us with each top-level decl, including those nested in + // a decl chain, so we may be passed decls that are already serialized. + for (const_iterator I=begin(), E=end(); I!=E; ++I) + if (!Sezr.isRegistered(*I)) + Sezr.EmitOwnedPtr(*I); + + Sezr.ExitBlock(); + + // ===---------------------------------------------------===/ + // Serialize the "Translation Unit" metadata. + // ===---------------------------------------------------===/ + + // Emit ASTContext. + Sezr.EnterBlock(ASTContextBlock); + Sezr.EmitOwnedPtr(Context); + Sezr.ExitBlock(); + + Sezr.EnterBlock(BasicMetadataBlock); + + // Block for SourceManager, LangOptions, and Target. Allows easy skipping + // around to the block for the Selectors during deserialization. + Sezr.EnterBlock(); + + // Emit the SourceManager. + Sezr.Emit(Context->getSourceManager()); + + // Emit the LangOptions. + Sezr.Emit(LangOpts); + + // Emit the Target. + Sezr.EmitPtr(&Context->Target); + Sezr.EmitCStr(Context->Target.getTargetTriple()); + + Sezr.ExitBlock(); // exit "BasicMetadataBlock" + + // Emit the Selectors. + Sezr.Emit(Context->Selectors); + + // Emit the Identifier Table. + Sezr.Emit(Context->Idents); + + Sezr.ExitBlock(); // exit "ASTContextBlock" +} + +TranslationUnit* +clang::ReadASTBitcodeFile(const llvm::sys::Path& Filename, FileManager& FMgr) { + + // Create the memory buffer that contains the contents of the file. + llvm::OwningPtr + MBuffer(llvm::MemoryBuffer::getFile(Filename.c_str(), + strlen(Filename.c_str()))); + + if (!MBuffer) { + // FIXME: Provide diagnostic. + return NULL; + } + + // Check if the file is of the proper length. + if (MBuffer->getBufferSize() & 0x3) { + // FIXME: Provide diagnostic: "Length should be a multiple of 4 bytes." + return NULL; + } + + // Create the bitstream reader. + unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart(); + llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize()); + + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xF || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0x0) { + // FIXME: Provide diagnostic. + return NULL; + } + + // Create the deserializer. + llvm::Deserializer Dezr(Stream); + + return TranslationUnit::Create(Dezr,FMgr); +} + +TranslationUnit* TranslationUnit::Create(llvm::Deserializer& Dezr, + FileManager& FMgr) { + + // Create the translation unit object. + TranslationUnit* TU = new TranslationUnit(); + + // ===---------------------------------------------------===/ + // Deserialize the "Translation Unit" metadata. + // ===---------------------------------------------------===/ + + // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock + // (which will appear earlier) and record its location. + + bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock); + assert (FoundBlock); + + llvm::Deserializer::Location ASTContextBlockLoc = + Dezr.getCurrentBlockLocation(); + + FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock); + assert (FoundBlock); + + // Read the SourceManager. + SourceManager::CreateAndRegister(Dezr,FMgr); + + // Read the LangOptions. + TU->LangOpts.Read(Dezr); + + { // Read the TargetInfo. + llvm::SerializedPtrID PtrID = Dezr.ReadPtrID(); + char* triple = Dezr.ReadCStr(NULL,0,true); + Dezr.RegisterPtr(PtrID,TargetInfo::CreateTargetInfo(std::string(triple))); + delete [] triple; + } + + // For Selectors, we must read the identifier table first because the + // SelectorTable depends on the identifiers being already deserialized. + llvm::Deserializer::Location SelectorBlkLoc = Dezr.getCurrentBlockLocation(); + Dezr.SkipBlock(); + + // Read the identifier table. + IdentifierTable::CreateAndRegister(Dezr); + + // Now jump back and read the selectors. + Dezr.JumpTo(SelectorBlkLoc); + SelectorTable::CreateAndRegister(Dezr); + + // Now jump back to ASTContextBlock and read the ASTContext. + Dezr.JumpTo(ASTContextBlockLoc); + TU->Context = Dezr.ReadOwnedPtr(); + + // "Rewind" the stream. Find the block with the serialized top-level decls. + Dezr.Rewind(); + FoundBlock = Dezr.SkipToBlock(DeclsBlock); + assert (FoundBlock); + llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation(); + + while (!Dezr.FinishedBlock(DeclBlockLoc)) + TU->AddTopLevelDecl(Dezr.ReadOwnedPtr()); + + return TU; +} + diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp new file mode 100644 index 00000000000..80b2d5cb93d --- /dev/null +++ b/clang/lib/AST/Type.cpp @@ -0,0 +1,978 @@ +//===--- Type.cpp - Type representation and manipulation ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements type-related functionality. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/StringExtras.h" +#include + +using namespace clang; + +Type::~Type() {} + +/// isVoidType - Helper method to determine if this is the 'void' type. +bool Type::isVoidType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() == BuiltinType::Void; + return false; +} + +bool Type::isObjectType() const { + if (isa(CanonicalType)) + return false; + else if (CanonicalType->isIncompleteType()) + return false; + else + return true; +} + +bool Type::isDerivedType() const { + switch (CanonicalType->getTypeClass()) { + case Pointer: + case VariableArray: + case ConstantArray: + case IncompleteArray: + case FunctionProto: + case FunctionNoProto: + case Reference: + return true; + case Tagged: { + const TagType *TT = cast(CanonicalType); + const Decl::Kind Kind = TT->getDecl()->getKind(); + return Kind == Decl::Struct || Kind == Decl::Union; + } + default: + return false; + } +} + +bool Type::isStructureType() const { + if (const RecordType *RT = dyn_cast(CanonicalType)) + if (RT->getDecl()->getKind() == Decl::Struct) + return true; + return false; +} +bool Type::isUnionType() const { + if (const RecordType *RT = dyn_cast(CanonicalType)) + if (RT->getDecl()->getKind() == Decl::Union) + return true; + return false; +} + +bool Type::isComplexType() const { + if (const ComplexType *CT = dyn_cast(CanonicalType)) + return CT->getElementType()->isFloatingType(); + return false; +} + +bool Type::isComplexIntegerType() const { + // Check for GCC complex integer extension. + if (const ComplexType *CT = dyn_cast(CanonicalType)) + return CT->getElementType()->isIntegerType(); + return false; +} + +const ComplexType *Type::getAsComplexIntegerType() const { + // Are we directly a complex type? + if (const ComplexType *CTy = dyn_cast(this)) { + if (CTy->getElementType()->isIntegerType()) + return CTy; + } + // If the canonical form of this type isn't the right kind, reject it. + const ComplexType *CTy = dyn_cast(CanonicalType); + if (!CTy || !CTy->getElementType()->isIntegerType()) + return 0; + + // If this is a typedef for a complex type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsComplexIntegerType(); +} + +/// getDesugaredType - Return the specified type with any "sugar" removed from +/// type type. This takes off typedefs, typeof's etc. If the outer level of +/// the type is already concrete, it returns it unmodified. This is similar +/// to getting the canonical type, but it doesn't remove *all* typedefs. For +/// example, it return "T*" as "T*", (not as "int*"), because the pointer is +/// concrete. +const Type *Type::getDesugaredType() const { + if (const TypedefType *TDT = dyn_cast(this)) + return TDT->LookThroughTypedefs().getTypePtr(); + if (const TypeOfExpr *TOE = dyn_cast(this)) + return TOE->getUnderlyingExpr()->getType().getTypePtr(); + if (const TypeOfType *TOT = dyn_cast(this)) + return TOT->getUnderlyingType().getTypePtr(); + return this; +} + + +const BuiltinType *Type::getAsBuiltinType() const { + // If this is directly a builtin type, return it. + if (const BuiltinType *BTy = dyn_cast(this)) + return BTy; + + // If the canonical form of this type isn't a builtin type, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsBuiltinType(); + return 0; + } + + // If this is a typedef for a builtin type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsBuiltinType(); +} + +const FunctionType *Type::getAsFunctionType() const { + // If this is directly a function type, return it. + if (const FunctionType *FTy = dyn_cast(this)) + return FTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsFunctionType(); + return 0; + } + + // If this is a typedef for a function type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsFunctionType(); +} + +const PointerType *Type::getAsPointerType() const { + // If this is directly a pointer type, return it. + if (const PointerType *PTy = dyn_cast(this)) + return PTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsPointerType(); + return 0; + } + + // If this is a typedef for a pointer type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsPointerType(); +} + +const ReferenceType *Type::getAsReferenceType() const { + // If this is directly a reference type, return it. + if (const ReferenceType *RTy = dyn_cast(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsReferenceType(); + return 0; + } + + // If this is a typedef for a reference type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsReferenceType(); +} + +const ArrayType *Type::getAsArrayType() const { + // If this is directly an array type, return it. + if (const ArrayType *ATy = dyn_cast(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsArrayType(); + return 0; + } + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsArrayType(); +} + +const ConstantArrayType *Type::getAsConstantArrayType() const { + // If this is directly a constant array type, return it. + if (const ConstantArrayType *ATy = dyn_cast(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsConstantArrayType(); + return 0; + } + + // If this is a typedef for a constant array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsConstantArrayType(); +} + +const VariableArrayType *Type::getAsVariableArrayType() const { + // If this is directly a variable array type, return it. + if (const VariableArrayType *ATy = dyn_cast(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsVariableArrayType(); + return 0; + } + + // If this is a typedef for a variable array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsVariableArrayType(); +} + +/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length +/// array types and types that contain variable array types in their +/// declarator +bool Type::isVariablyModifiedType() const { + // A VLA is a veriably modified type + if (getAsVariableArrayType()) + return true; + + // An array can contain a variably modified type + if (const ArrayType* AT = getAsArrayType()) + return AT->getElementType()->isVariablyModifiedType(); + + // A pointer can point to a variably modified type + if (const PointerType* PT = getAsPointerType()) + return PT->getPointeeType()->isVariablyModifiedType(); + + // A function can return a variably modified type + // This one isn't completely obvious, but it follows from the + // definition in C99 6.7.5p3. Because of this rule, it's + // illegal to declare a function returning a variably modified type. + if (const FunctionType* FT = getAsFunctionType()) + return FT->getResultType()->isVariablyModifiedType(); + + return false; +} + +bool Type::isIncompleteArrayType() const { + return isa(CanonicalType); +} + +const IncompleteArrayType *Type::getAsIncompleteArrayType() const { + // If this is directly a variable array type, return it. + if (const IncompleteArrayType *ATy = dyn_cast(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsIncompleteArrayType(); + return 0; + } + + // If this is a typedef for a variable array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsIncompleteArrayType(); +} + +const RecordType *Type::getAsRecordType() const { + // If this is directly a reference type, return it. + if (const RecordType *RTy = dyn_cast(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsRecordType(); + return 0; + } + + // If this is a typedef for a record type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsRecordType(); +} + +const RecordType *Type::getAsStructureType() const { + // If this is directly a structure type, return it. + if (const RecordType *RT = dyn_cast(this)) { + if (RT->getDecl()->getKind() == Decl::Struct) + return RT; + } + + // If the canonical form of this type isn't the right kind, reject it. + if (const RecordType *RT = dyn_cast(CanonicalType)) { + if (RT->getDecl()->getKind() != Decl::Struct) + return 0; + + // If this is a typedef for a structure type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsStructureType(); + } + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsStructureType(); + return 0; +} + +const RecordType *Type::getAsUnionType() const { + // If this is directly a union type, return it. + if (const RecordType *RT = dyn_cast(this)) { + if (RT->getDecl()->getKind() == Decl::Union) + return RT; + } + + // If the canonical form of this type isn't the right kind, reject it. + if (const RecordType *RT = dyn_cast(CanonicalType)) { + if (RT->getDecl()->getKind() != Decl::Union) + return 0; + + // If this is a typedef for a union type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsUnionType(); + } + + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsUnionType(); + return 0; +} + +const ComplexType *Type::getAsComplexType() const { + // Are we directly a complex type? + if (const ComplexType *CTy = dyn_cast(this)) + return CTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsComplexType(); + return 0; + } + + // If this is a typedef for a complex type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsComplexType(); +} + +const VectorType *Type::getAsVectorType() const { + // Are we directly a vector type? + if (const VectorType *VTy = dyn_cast(this)) + return VTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsVectorType(); + return 0; + } + + // If this is a typedef for a vector type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsVectorType(); +} + +const OCUVectorType *Type::getAsOCUVectorType() const { + // Are we directly an OpenCU vector type? + if (const OCUVectorType *VTy = dyn_cast(this)) + return VTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsOCUVectorType(); + return 0; + } + + // If this is a typedef for an ocuvector type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsOCUVectorType(); +} + +bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongLong; + if (const TagType *TT = dyn_cast(CanonicalType)) + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + if (const VectorType *VT = dyn_cast(CanonicalType)) + return VT->getElementType()->isIntegerType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isIntegerType(); + return false; +} + +bool Type::isIntegralType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongLong; + if (const TagType *TT = dyn_cast(CanonicalType)) + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isIntegralType(); + return false; +} + +bool Type::isEnumeralType() const { + if (const TagType *TT = dyn_cast(CanonicalType)) + return TT->getDecl()->getKind() == Decl::Enum; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isEnumeralType(); + return false; +} + +bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isBooleanType(); + return false; +} + +bool Type::isCharType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() == BuiltinType::Char_U || + BT->getKind() == BuiltinType::UChar || + BT->getKind() == BuiltinType::Char_S || + BT->getKind() == BuiltinType::SChar; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isCharType(); + return false; +} + +/// isSignedIntegerType - Return true if this is an integer type that is +/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], +/// an enum decl which has a signed representation, or a vector of signed +/// integer element type. +bool Type::isSignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) { + return BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::LongLong; + } + + if (const TagType *TT = dyn_cast(CanonicalType)) + if (const EnumDecl *ED = dyn_cast(TT->getDecl())) + return ED->getIntegerType()->isSignedIntegerType(); + + if (const VectorType *VT = dyn_cast(CanonicalType)) + return VT->getElementType()->isSignedIntegerType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isSignedIntegerType(); + return false; +} + +/// isUnsignedIntegerType - Return true if this is an integer type that is +/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum +/// decl which has an unsigned representation, or a vector of unsigned integer +/// element type. +bool Type::isUnsignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) { + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::ULongLong; + } + + if (const TagType *TT = dyn_cast(CanonicalType)) + if (const EnumDecl *ED = dyn_cast(TT->getDecl())) + return ED->getIntegerType()->isUnsignedIntegerType(); + + if (const VectorType *VT = dyn_cast(CanonicalType)) + return VT->getElementType()->isUnsignedIntegerType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isUnsignedIntegerType(); + return false; +} + +bool Type::isFloatingType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + if (const ComplexType *CT = dyn_cast(CanonicalType)) + return CT->getElementType()->isFloatingType(); + if (const VectorType *VT = dyn_cast(CanonicalType)) + return VT->getElementType()->isFloatingType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isFloatingType(); + return false; +} + +bool Type::isRealFloatingType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + if (const VectorType *VT = dyn_cast(CanonicalType)) + return VT->getElementType()->isRealFloatingType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isRealFloatingType(); + return false; +} + +bool Type::isRealType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongDouble; + if (const TagType *TT = dyn_cast(CanonicalType)) + return TT->getDecl()->getKind() == Decl::Enum; + if (const VectorType *VT = dyn_cast(CanonicalType)) + return VT->getElementType()->isRealType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isRealType(); + return false; +} + +bool Type::isArithmeticType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() != BuiltinType::Void; + if (const TagType *TT = dyn_cast(CanonicalType)) + if (const EnumDecl *ED = dyn_cast(TT->getDecl())) + // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). + // If a body isn't seen by the time we get here, return false. + return ED->isDefinition(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isArithmeticType(); + return isa(CanonicalType) || isa(CanonicalType); +} + +bool Type::isScalarType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() != BuiltinType::Void; + if (const TagType *TT = dyn_cast(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + return false; + } + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isScalarType(); + return isa(CanonicalType) || isa(CanonicalType) || + isa(CanonicalType); +} + +bool Type::isAggregateType() const { + if (const TagType *TT = dyn_cast(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Struct) + return true; + return false; + } + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isAggregateType(); + return isa(CanonicalType); +} + +/// isConstantSizeType - Return true if this is not a variable sized type, +/// according to the rules of C99 6.7.5p3. It is not legal to call this on +/// incomplete types. +bool Type::isConstantSizeType() const { + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isConstantSizeType(); + assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); + // The VAT must have a size, as it is known to be complete. + return !isa(CanonicalType); +} + +/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) +/// - a type that can describe objects, but which lacks information needed to +/// determine its size. +bool Type::isIncompleteType() const { + switch (CanonicalType->getTypeClass()) { + default: return false; + case ASQual: + return cast(CanonicalType)->getBaseType()->isIncompleteType(); + case Builtin: + // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never + // be completed. + return isVoidType(); + case Tagged: + // A tagged type (struct/union/enum/class) is incomplete if the decl is a + // forward declaration, but not a full definition (C99 6.2.5p22). + return !cast(CanonicalType)->getDecl()->isDefinition(); + case IncompleteArray: + // An array of unknown size is an incomplete type (C99 6.2.5p22). + return true; + } +} + +bool Type::isPromotableIntegerType() const { + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isPromotableIntegerType(); + const BuiltinType *BT = dyn_cast(CanonicalType); + if (!BT) return false; + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + return true; + default: + return false; + } +} + +const char *BuiltinType::getName() const { + switch (getKind()) { + default: assert(0 && "Unknown builtin type!"); + case Void: return "void"; + case Bool: return "_Bool"; + case Char_S: return "char"; + case Char_U: return "char"; + case SChar: return "signed char"; + case Short: return "short"; + case Int: return "int"; + case Long: return "long"; + case LongLong: return "long long"; + case UChar: return "unsigned char"; + case UShort: return "unsigned short"; + case UInt: return "unsigned int"; + case ULong: return "unsigned long"; + case ULongLong: return "unsigned long long"; + case Float: return "float"; + case Double: return "double"; + case LongDouble: return "long double"; + } +} + +void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result, + arg_type_iterator ArgTys, + unsigned NumArgs, bool isVariadic) { + ID.AddPointer(Result.getAsOpaquePtr()); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i].getAsOpaquePtr()); + ID.AddInteger(isVariadic); +} + +void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic()); +} + +void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, &Protocols[0], getNumProtocols()); +} + +void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, &Protocols[0], getNumProtocols()); +} + +/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to +/// potentially looking through *all* consequtive typedefs. This returns the +/// sum of the type qualifiers, so if you have: +/// typedef const int A; +/// typedef volatile A B; +/// looking through the typedefs for B will give you "const volatile A". +/// +QualType TypedefType::LookThroughTypedefs() const { + // Usually, there is only a single level of typedefs, be fast in that case. + QualType FirstType = getDecl()->getUnderlyingType(); + if (!isa(FirstType)) + return FirstType; + + // Otherwise, do the fully general loop. + unsigned TypeQuals = 0; + const TypedefType *TDT = this; + while (1) { + QualType CurType = TDT->getDecl()->getUnderlyingType(); + + + /// FIXME: + /// FIXME: This is incorrect for ASQuals! + /// FIXME: + TypeQuals |= CurType.getCVRQualifiers(); + + TDT = dyn_cast(CurType); + if (TDT == 0) + return QualType(CurType.getTypePtr(), TypeQuals); + } +} + +bool RecordType::classof(const Type *T) { + if (const TagType *TT = dyn_cast(T)) + return isa(TT->getDecl()); + return false; +} + + +//===----------------------------------------------------------------------===// +// Type Printing +//===----------------------------------------------------------------------===// + +void QualType::dump(const char *msg) const { + std::string R = "identifier"; + getAsStringInternal(R); + if (msg) + fprintf(stderr, "%s: %s\n", msg, R.c_str()); + else + fprintf(stderr, "%s\n", R.c_str()); +} + +static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { + // Note: funkiness to ensure we get a space only between quals. + bool NonePrinted = true; + if (TypeQuals & QualType::Const) + S += "const", NonePrinted = false; + if (TypeQuals & QualType::Volatile) + S += (NonePrinted+" volatile"), NonePrinted = false; + if (TypeQuals & QualType::Restrict) + S += (NonePrinted+" restrict"), NonePrinted = false; +} + +void QualType::getAsStringInternal(std::string &S) const { + if (isNull()) { + S += "NULL TYPE\n"; + return; + } + + // Print qualifiers as appropriate. + if (unsigned Tq = getCVRQualifiers()) { + std::string TQS; + AppendTypeQualList(TQS, Tq); + if (!S.empty()) + S = TQS + ' ' + S; + else + S = TQS; + } + + getTypePtr()->getAsStringInternal(S); +} + +void BuiltinType::getAsStringInternal(std::string &S) const { + if (S.empty()) { + S = getName(); + } else { + // Prefix the basic type, e.g. 'int X'. + S = ' ' + S; + S = getName() + S; + } +} + +void ComplexType::getAsStringInternal(std::string &S) const { + ElementType->getAsStringInternal(S); + S = "_Complex " + S; +} + +void ASQualType::getAsStringInternal(std::string &S) const { + S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; + BaseType->getAsStringInternal(S); +} + +void PointerType::getAsStringInternal(std::string &S) const { + S = '*' + S; + + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa(PointeeType.getTypePtr())) + S = '(' + S + ')'; + + PointeeType.getAsStringInternal(S); +} + +void ReferenceType::getAsStringInternal(std::string &S) const { + S = '&' + S; + + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa(ReferenceeType.getTypePtr())) + S = '(' + S + ')'; + + ReferenceeType.getAsStringInternal(S); +} + +void ConstantArrayType::getAsStringInternal(std::string &S) const { + S += '['; + S += llvm::utostr(getSize().getZExtValue()); + S += ']'; + + getElementType().getAsStringInternal(S); +} + +void IncompleteArrayType::getAsStringInternal(std::string &S) const { + S += "[]"; + + getElementType().getAsStringInternal(S); +} + +void VariableArrayType::getAsStringInternal(std::string &S) const { + S += '['; + + if (getIndexTypeQualifier()) { + AppendTypeQualList(S, getIndexTypeQualifier()); + S += ' '; + } + + if (getSizeModifier() == Static) + S += "static"; + else if (getSizeModifier() == Star) + S += '*'; + + if (getSizeExpr()) { + std::ostringstream s; + getSizeExpr()->printPretty(s); + S += s.str(); + } + S += ']'; + + getElementType().getAsStringInternal(S); +} + +void VectorType::getAsStringInternal(std::string &S) const { + S += " __attribute__((__vector_size__("; + // FIXME: should multiply by element size somehow. + S += llvm::utostr_32(NumElements*4); // convert back to bytes. + S += ")))"; + ElementType.getAsStringInternal(S); +} + +void OCUVectorType::getAsStringInternal(std::string &S) const { + S += " __attribute__((ocu_vector_type("; + S += llvm::utostr_32(NumElements); + S += ")))"; + ElementType.getAsStringInternal(S); +} + +void TypeOfExpr::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. + InnerString = ' ' + InnerString; + std::ostringstream s; + getUnderlyingExpr()->printPretty(s); + InnerString = "typeof(" + s.str() + ")" + InnerString; +} + +void TypeOfType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. + InnerString = ' ' + InnerString; + std::string Tmp; + getUnderlyingType().getAsStringInternal(Tmp); + InnerString = "typeof(" + Tmp + ")" + InnerString; +} + +void FunctionTypeNoProto::getAsStringInternal(std::string &S) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "()"; + getResultType().getAsStringInternal(S); +} + +void FunctionTypeProto::getAsStringInternal(std::string &S) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "("; + std::string Tmp; + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { + if (i) S += ", "; + getArgType(i).getAsStringInternal(Tmp); + S += Tmp; + Tmp.clear(); + } + + if (isVariadic()) { + if (getNumArgs()) + S += ", "; + S += "..."; + } else if (getNumArgs() == 0) { + // Do not emit int() if we have a proto, emit 'int(void)'. + S += "void"; + } + + S += ")"; + getResultType().getAsStringInternal(S); +} + + +void TypedefType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + +void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + +void ObjCQualifiedInterfaceType::getAsStringInternal( + std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjCQIString = getDecl()->getName(); + ObjCQIString += '<'; + int num = getNumProtocols(); + for (int i = 0; i < num; i++) { + ObjCQIString += getProtocols(i)->getName(); + if (i < num-1) + ObjCQIString += ','; + } + ObjCQIString += '>'; + InnerString = ObjCQIString + InnerString; +} + +void ObjCQualifiedIdType::getAsStringInternal( + std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjCQIString = "id"; + ObjCQIString += '<'; + int num = getNumProtocols(); + for (int i = 0; i < num; i++) { + ObjCQIString += getProtocols(i)->getName(); + if (i < num-1) + ObjCQIString += ','; + } + ObjCQIString += '>'; + InnerString = ObjCQIString + InnerString; +} + +void TagType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + + const char *Kind = getDecl()->getKindName(); + const char *ID; + if (const IdentifierInfo *II = getDecl()->getIdentifier()) + ID = II->getName(); + else + ID = ""; + + InnerString = std::string(Kind) + " " + ID + InnerString; +} diff --git a/clang/lib/AST/TypeSerialization.cpp b/clang/lib/AST/TypeSerialization.cpp new file mode 100644 index 00000000000..55c0a48a00d --- /dev/null +++ b/clang/lib/AST/TypeSerialization.cpp @@ -0,0 +1,293 @@ +//===--- TypeSerialization.cpp - Serialization of Decls ---------*- 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 methods that implement bitcode serialization for Types. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Type.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; +using llvm::Serializer; +using llvm::Deserializer; +using llvm::SerializedPtrID; + + +void QualType::Emit(Serializer& S) const { + S.EmitPtr(getTypePtr()); + S.EmitInt(getCVRQualifiers()); +} + +QualType QualType::ReadVal(Deserializer& D) { + QualType Q; + D.ReadUIntPtr(Q.ThePtr,false); + Q.ThePtr |= D.ReadInt(); + return Q; +} + +void QualType::ReadBackpatch(Deserializer& D) { + D.ReadUIntPtr(ThePtr,true); + ThePtr |= D.ReadInt(); +} + +//===----------------------------------------------------------------------===// +// Type Serialization: Dispatch code to handle specific types. +//===----------------------------------------------------------------------===// + +void Type::Emit(Serializer& S) const { + S.EmitInt(getTypeClass()); + S.EmitPtr(this); + + if (!isa(this)) + EmitImpl(S); +} + +void Type::EmitImpl(Serializer& S) const { + assert (false && "Serializization for type not supported."); +} + +void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { + Type::TypeClass K = static_cast(D.ReadInt()); + SerializedPtrID PtrID = D.ReadPtrID(); + + switch (K) { + default: + assert (false && "Deserialization for type not supported."); + break; + + case Type::Builtin: + assert (i < Context.getTypes().size()); + assert (isa(Context.getTypes()[i])); + D.RegisterPtr(PtrID,Context.getTypes()[i]); + break; + + case Type::ASQual: + D.RegisterPtr(PtrID,ASQualType::CreateImpl(Context,D)); + break; + + case Type::Complex: + D.RegisterPtr(PtrID,ComplexType::CreateImpl(Context,D)); + break; + + case Type::ConstantArray: + D.RegisterPtr(PtrID,ConstantArrayType::CreateImpl(Context,D)); + break; + + case Type::FunctionNoProto: + D.RegisterPtr(PtrID,FunctionTypeNoProto::CreateImpl(Context,D)); + break; + + case Type::FunctionProto: + D.RegisterPtr(PtrID,FunctionTypeProto::CreateImpl(Context,D)); + break; + + case Type::IncompleteArray: + D.RegisterPtr(PtrID,IncompleteArrayType::CreateImpl(Context,D)); + break; + + case Type::Pointer: + D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D)); + break; + + case Type::Tagged: + D.RegisterPtr(PtrID,TagType::CreateImpl(Context,D)); + break; + + case Type::TypeName: + D.RegisterPtr(PtrID,TypedefType::CreateImpl(Context,D)); + break; + + case Type::VariableArray: + D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D)); + break; + } +} + +//===----------------------------------------------------------------------===// +// ASQualType +//===----------------------------------------------------------------------===// + +void ASQualType::EmitImpl(Serializer& S) const { + S.EmitPtr(getBaseType()); + S.EmitInt(getAddressSpace()); +} + +Type* ASQualType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType BaseTy = QualType::ReadVal(D); + unsigned AddressSpace = D.ReadInt(); + return Context.getASQualType(BaseTy, AddressSpace).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// ComplexType +//===----------------------------------------------------------------------===// + +void ComplexType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); +} + +Type* ComplexType::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getComplexType(QualType::ReadVal(D)).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// ConstantArray +//===----------------------------------------------------------------------===// + +void ConstantArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); + S.Emit(Size); +} + +Type* ConstantArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + + llvm::APInt Size; + D.Read(Size); + + return Context.getConstantArrayType(ElTy,Size,am,ITQ).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// FunctionTypeNoProto +//===----------------------------------------------------------------------===// + +void FunctionTypeNoProto::EmitImpl(Serializer& S) const { + S.Emit(getResultType()); +} + +Type* FunctionTypeNoProto::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getFunctionTypeNoProto(QualType::ReadVal(D)).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// FunctionTypeProto +//===----------------------------------------------------------------------===// + +void FunctionTypeProto::EmitImpl(Serializer& S) const { + S.Emit(getResultType()); + S.EmitBool(isVariadic()); + S.EmitInt(getNumArgs()); + + for (arg_type_iterator I=arg_type_begin(), E=arg_type_end(); I!=E; ++I) + S.Emit(*I); +} + +Type* FunctionTypeProto::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ResultType = QualType::ReadVal(D); + bool isVariadic = D.ReadBool(); + unsigned NumArgs = D.ReadInt(); + + llvm::SmallVector Args; + + for (unsigned j = 0; j < NumArgs; ++j) + Args.push_back(QualType::ReadVal(D)); + + return Context.getFunctionType(ResultType,&*Args.begin(), + NumArgs,isVariadic).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// PointerType +//===----------------------------------------------------------------------===// + +void PointerType::EmitImpl(Serializer& S) const { + S.Emit(getPointeeType()); +} + +Type* PointerType::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getPointerType(QualType::ReadVal(D)).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// TagType +//===----------------------------------------------------------------------===// + +void TagType::EmitImpl(Serializer& S) const { + S.EmitOwnedPtr(getDecl()); +} + +Type* TagType::CreateImpl(ASTContext& Context, Deserializer& D) { + std::vector& Types = + const_cast&>(Context.getTypes()); + + TagType* T = new TagType(NULL,QualType()); + Types.push_back(T); + + // Deserialize the decl. + T->decl = cast(D.ReadOwnedPtr()); + + return T; +} + +//===----------------------------------------------------------------------===// +// TypedefType +//===----------------------------------------------------------------------===// + +void TypedefType::EmitImpl(Serializer& S) const { + S.Emit(QualType((Type*)this,0).getCanonicalType()); + S.EmitPtr(Decl); +} + +Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) { + std::vector& Types = + const_cast&>(Context.getTypes()); + + TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D)); + Types.push_back(T); + + D.ReadPtr(T->Decl); // May be backpatched. + return T; +} + +//===----------------------------------------------------------------------===// +// VariableArrayType +//===----------------------------------------------------------------------===// + +void VariableArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); + S.EmitOwnedPtr(SizeExpr); +} + +Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + Expr* SizeExpr = D.ReadOwnedPtr(); + + return Context.getVariableArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// IncompleteArrayType +//===----------------------------------------------------------------------===// + +void IncompleteArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); +} + +Type* IncompleteArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + + return Context.getIncompleteArrayType(ElTy,am,ITQ).getTypePtr(); +} diff --git a/clang/lib/Analysis/BasicValueFactory.cpp b/clang/lib/Analysis/BasicValueFactory.cpp new file mode 100644 index 00000000000..88b360d1d0e --- /dev/null +++ b/clang/lib/Analysis/BasicValueFactory.cpp @@ -0,0 +1,167 @@ +//=== BasicValueFactory.cpp - Basic values for Path Sens analysis --*- 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 BasicValueFactory, a class that manages the lifetime +// of APSInt objects and symbolic constraints used by GRExprEngine +// and related classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/BasicValueFactory.h" + +using namespace clang; + +BasicValueFactory::~BasicValueFactory() { + // Note that the dstor for the contents of APSIntSet will never be called, + // so we iterate over the set and invoke the dstor for each APSInt. This + // frees an aux. memory allocated to represent very large constants. + for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I) + I->getValue().~APSInt(); +} + +const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { + llvm::FoldingSetNodeID ID; + void* InsertPos; + typedef llvm::FoldingSetNodeWrapper FoldNodeTy; + + X.Profile(ID); + FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); + + if (!P) { + P = (FoldNodeTy*) BPAlloc.Allocate(); + new (P) FoldNodeTy(X); + APSIntSet.InsertNode(P, InsertPos); + } + + return *P; +} + +const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, + bool isUnsigned) { + llvm::APSInt V(BitWidth, isUnsigned); + V = X; + return getValue(V); +} + +const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { + + unsigned bits = Ctx.getTypeSize(T); + llvm::APSInt V(bits, T->isUnsignedIntegerType()); + V = X; + return getValue(V); +} + +const SymIntConstraint& +BasicValueFactory::getConstraint(SymbolID sym, BinaryOperator::Opcode Op, + const llvm::APSInt& V) { + + llvm::FoldingSetNodeID ID; + SymIntConstraint::Profile(ID, sym, Op, V); + void* InsertPos; + + SymIntConstraint* C = SymIntCSet.FindNodeOrInsertPos(ID, InsertPos); + + if (!C) { + C = (SymIntConstraint*) BPAlloc.Allocate(); + new (C) SymIntConstraint(sym, Op, V); + SymIntCSet.InsertNode(C, InsertPos); + } + + return *C; +} + +const llvm::APSInt* +BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt& V1, const llvm::APSInt& V2) { + + switch (Op) { + default: + assert (false && "Invalid Opcode."); + + case BinaryOperator::Mul: + return &getValue( V1 * V2 ); + + case BinaryOperator::Div: + return &getValue( V1 / V2 ); + + case BinaryOperator::Rem: + return &getValue( V1 % V2 ); + + case BinaryOperator::Add: + return &getValue( V1 + V2 ); + + case BinaryOperator::Sub: + return &getValue( V1 - V2 ); + + case BinaryOperator::Shl: { + + // FIXME: This logic should probably go higher up, where we can + // test these conditions symbolically. + + // FIXME: Expand these checks to include all undefined behavior. + + if (V2.isSigned() && V2.isNegative()) + return NULL; + + uint64_t Amt = V2.getZExtValue(); + + if (Amt > V1.getBitWidth()) + return NULL; + + return &getValue( V1.operator<<( (unsigned) Amt )); + } + + case BinaryOperator::Shr: { + + // FIXME: This logic should probably go higher up, where we can + // test these conditions symbolically. + + // FIXME: Expand these checks to include all undefined behavior. + + if (V2.isSigned() && V2.isNegative()) + return NULL; + + uint64_t Amt = V2.getZExtValue(); + + if (Amt > V1.getBitWidth()) + return NULL; + + return &getValue( V1.operator>>( (unsigned) Amt )); + } + + case BinaryOperator::LT: + return &getTruthValue( V1 < V2 ); + + case BinaryOperator::GT: + return &getTruthValue( V1 > V2 ); + + case BinaryOperator::LE: + return &getTruthValue( V1 <= V2 ); + + case BinaryOperator::GE: + return &getTruthValue( V1 >= V2 ); + + case BinaryOperator::EQ: + return &getTruthValue( V1 == V2 ); + + case BinaryOperator::NE: + return &getTruthValue( V1 != V2 ); + + // Note: LAnd, LOr, Comma are handled specially by higher-level logic. + + case BinaryOperator::And: + return &getValue( V1 & V2 ); + + case BinaryOperator::Or: + return &getValue( V1 | V2 ); + + case BinaryOperator::Xor: + return &getValue( V1 ^ V2 ); + } +} diff --git a/clang/lib/Analysis/CFRefCount.cpp b/clang/lib/Analysis/CFRefCount.cpp new file mode 100644 index 00000000000..77bbba25ea3 --- /dev/null +++ b/clang/lib/Analysis/CFRefCount.cpp @@ -0,0 +1,796 @@ +// CFRefCount.cpp - Transfer functions for tracking simple values -*- 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 methods for CFRefCount, which implements +// a reference count checker for Core Foundation (Mac OS X). +// +//===----------------------------------------------------------------------===// + +#include "GRSimpleVals.h" +#include "clang/Analysis/PathSensitive/ValueState.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Analysis/LocalCheckers.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include + +using namespace clang; + +namespace { + enum ArgEffect { IncRef, DecRef, DoNothing }; + typedef std::vector ArgEffects; +} + +namespace llvm { + template <> struct FoldingSetTrait { + static void Profile(const ArgEffects& X, FoldingSetNodeID ID) { + for (ArgEffects::const_iterator I = X.begin(), E = X.end(); I!= E; ++I) + ID.AddInteger((unsigned) *I); + } + + static void Profile(ArgEffects& X, FoldingSetNodeID ID) { + Profile(X, ID); + } + }; +} // end llvm namespace + +namespace { + +class RetEffect { +public: + enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 }; + +private: + unsigned Data; + RetEffect(Kind k, unsigned D) { Data = (Data << 2) | (unsigned) k; } + +public: + + Kind getKind() const { return (Kind) (Data & 0x3); } + + unsigned getValue() const { + assert(getKind() == Alias); + return Data & ~0x3; + } + + static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); } + + static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); } + + static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); } + + operator Kind() const { return getKind(); } + + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); } +}; + + +class CFRefSummary : public llvm::FoldingSetNode { + ArgEffects* Args; + RetEffect Ret; +public: + + CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {} + + unsigned getNumArgs() const { return Args->size(); } + + ArgEffect getArg(unsigned idx) const { + assert (idx < getNumArgs()); + return (*Args)[idx]; + } + + RetEffect getRet() const { + return Ret; + } + + typedef ArgEffects::const_iterator arg_iterator; + + arg_iterator begin_args() const { return Args->begin(); } + arg_iterator end_args() const { return Args->end(); } + + static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects* A, RetEffect R) { + ID.AddPointer(A); + ID.Add(R); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, Args, Ret); + } +}; + + +class CFRefSummaryManager { + typedef llvm::FoldingSet > AESetTy; + typedef llvm::FoldingSet SummarySetTy; + typedef llvm::DenseMap SummaryMapTy; + + SummarySetTy SummarySet; + SummaryMapTy SummaryMap; + AESetTy AESet; + llvm::BumpPtrAllocator BPAlloc; + + ArgEffects ScratchArgs; + + + ArgEffects* getArgEffects(); + + CFRefSummary* getCannedCFSummary(FunctionTypeProto* FT, bool isRetain); + + CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName); + + CFRefSummary* getCFSummaryCreateRule(FunctionTypeProto* FT); + CFRefSummary* getCFSummaryGetRule(FunctionTypeProto* FT); + + CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE); + +public: + CFRefSummaryManager() {} + ~CFRefSummaryManager(); + + CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx); +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Implementation of checker data structures. +//===----------------------------------------------------------------------===// + +CFRefSummaryManager::~CFRefSummaryManager() { + + // FIXME: The ArgEffects could eventually be allocated from BPAlloc, + // mitigating the need to do explicit cleanup of the + // Argument-Effect summaries. + + for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I) + I->getValue().~ArgEffects(); +} + +ArgEffects* CFRefSummaryManager::getArgEffects() { + + assert (!ScratchArgs.empty()); + + llvm::FoldingSetNodeID profile; + profile.Add(ScratchArgs); + void* InsertPos; + + llvm::FoldingSetNodeWrapper* E = + AESet.FindNodeOrInsertPos(profile, InsertPos); + + if (E) { + ScratchArgs.clear(); + return &E->getValue(); + } + + E = (llvm::FoldingSetNodeWrapper*) + BPAlloc.Allocate >(); + + new (E) llvm::FoldingSetNodeWrapper(ScratchArgs); + AESet.InsertNode(E, InsertPos); + + ScratchArgs.clear(); + return &E->getValue(); +} + +CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE, + RetEffect RE) { + + llvm::FoldingSetNodeID profile; + CFRefSummary::Profile(profile, AE, RE); + void* InsertPos; + + CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos); + + if (Summ) + return Summ; + + Summ = (CFRefSummary*) BPAlloc.Allocate(); + new (Summ) CFRefSummary(AE, RE); + SummarySet.InsertNode(Summ, InsertPos); + + return Summ; +} + + +CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD, + ASTContext& Ctx) { + + SourceLocation Loc = FD->getLocation(); + + if (!Loc.isFileID()) + return NULL; + + { // Look into our cache of summaries to see if we have already computed + // a summary for this FunctionDecl. + + SummaryMapTy::iterator I = SummaryMap.find(FD); + + if (I != SummaryMap.end()) + return I->second; + } + +#if 0 + SourceManager& SrcMgr = Ctx.getSourceManager(); + unsigned fid = Loc.getFileID(); + const FileEntry* FE = SrcMgr.getFileEntryForID(fid); + + if (!FE) + return NULL; + + const char* DirName = FE->getDir()->getName(); + assert (DirName); + assert (strlen(DirName) > 0); + + if (!strstr(DirName, "CoreFoundation")) { + SummaryMap[FD] = NULL; + return NULL; + } +#endif + + const char* FName = FD->getIdentifier()->getName(); + + if (FName[0] == 'C' && FName[1] == 'F') { + CFRefSummary* S = getCFSummary(FD, FName); + SummaryMap[FD] = S; + return S; + } + + return NULL; +} + +CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD, + const char* FName) { + + // For now, only generate summaries for functions that have a prototype. + + FunctionTypeProto* FT = + dyn_cast(FD->getType().getTypePtr()); + + if (!FT) + return NULL; + + FName += 2; + + if (strcmp(FName, "Retain") == 0) + return getCannedCFSummary(FT, true); + + if (strcmp(FName, "Release") == 0) + return getCannedCFSummary(FT, false); + + assert (ScratchArgs.empty()); + bool usesCreateRule = false; + + if (strstr(FName, "Create")) + usesCreateRule = true; + + if (!usesCreateRule && strstr(FName, "Copy")) + usesCreateRule = true; + + if (usesCreateRule) + return getCFSummaryCreateRule(FT); + + if (strstr(FName, "Get")) + return getCFSummaryGetRule(FT); + + return NULL; +} + +CFRefSummary* CFRefSummaryManager::getCannedCFSummary(FunctionTypeProto* FT, + bool isRetain) { + + if (FT->getNumArgs() != 1) + return NULL; + + TypedefType* ArgT = dyn_cast(FT->getArgType(0).getTypePtr()); + + if (!ArgT) + return NULL; + + // For CFRetain/CFRelease, the first (and only) argument is of type + // "CFTypeRef". + + const char* TDName = ArgT->getDecl()->getIdentifier()->getName(); + assert (TDName); + + if (strcmp("CFTypeRef", TDName) == 0) + return NULL; + + if (!ArgT->isPointerType()) + return NULL; + + // Check the return type. It should also be "CFTypeRef". + + QualType RetTy = FT->getResultType(); + + if (RetTy.getTypePtr() != ArgT) + return NULL; + + // The function's interface checks out. Generate a canned summary. + + assert (ScratchArgs.empty()); + ScratchArgs.push_back(isRetain ? IncRef : DecRef); + + return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0)); +} + +static bool isCFRefType(QualType T) { + + if (!T->isPointerType()) + return false; + + // Check the typedef for the name "CF" and the substring "Ref". + + TypedefType* TD = dyn_cast(T.getTypePtr()); + + if (!TD) + return false; + + const char* TDName = TD->getDecl()->getIdentifier()->getName(); + assert (TDName); + + if (TDName[0] != 'C' || TDName[1] != 'F') + return false; + + if (strstr(TDName, "Ref") == 0) + return false; + + return true; +} + + +CFRefSummary* +CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) { + + if (!isCFRefType(FT->getResultType())) + return NULL; + + assert (ScratchArgs.empty()); + + // FIXME: Add special-cases for functions that retain/release. For now + // just handle the default case. + + for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i) + ScratchArgs.push_back(DoNothing); + + return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned()); +} + +CFRefSummary* +CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) { + + if (!isCFRefType(FT->getResultType())) + return NULL; + + assert (ScratchArgs.empty()); + + // FIXME: Add special-cases for functions that retain/release. For now + // just handle the default case. + + for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i) + ScratchArgs.push_back(DoNothing); + + return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned()); +} + +//===----------------------------------------------------------------------===// +// Transfer functions. +//===----------------------------------------------------------------------===// + +namespace { + +class RefVal { + unsigned Data; + + RefVal(unsigned K, unsigned D) : Data((D << 3) | K) { + assert ((K & ~0x5) == 0x0); + } + + RefVal(unsigned K) : Data(K) { + assert ((K & ~0x5) == 0x0); + } + +public: + enum Kind { Owned = 0, AcqOwned = 1, NotOwned = 2, Released = 3, + ErrorUseAfterRelease = 4, ErrorReleaseNotOwned = 5 }; + + + Kind getKind() const { return (Kind) (Data & 0x5); } + + unsigned getCount() const { + assert (getKind() == Owned || getKind() == AcqOwned); + return Data >> 3; + } + + static bool isError(Kind k) { return k >= ErrorUseAfterRelease; } + + static RefVal makeOwned(unsigned Count) { return RefVal(Owned, Count); } + static RefVal makeAcqOwned(unsigned Count) { return RefVal(AcqOwned, Count); } + static RefVal makeNotOwned() { return RefVal(NotOwned); } + static RefVal makeReleased() { return RefVal(Released); } + static RefVal makeUseAfterRelease() { return RefVal(ErrorUseAfterRelease); } + static RefVal makeReleaseNotOwned() { return RefVal(ErrorReleaseNotOwned); } + + bool operator==(const RefVal& X) const { return Data == X.Data; } + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); } + + void print(std::ostream& Out) const; +}; + +void RefVal::print(std::ostream& Out) const { + switch (getKind()) { + default: assert(false); + case Owned: + Out << "Owned(" << getCount() << ")"; + break; + + case AcqOwned: + Out << "Acquired-Owned(" << getCount() << ")"; + break; + + case NotOwned: + Out << "Not-Owned"; + break; + + case Released: + Out << "Released"; + break; + + case ErrorUseAfterRelease: + Out << "Use-After-Release [ERROR]"; + break; + + case ErrorReleaseNotOwned: + Out << "Release of Not-Owned [ERROR]"; + break; + } +} + +class CFRefCount : public GRSimpleVals { + + // Type definitions. + + typedef llvm::ImmutableMap RefBindings; + typedef RefBindings::Factory RefBFactoryTy; + + typedef llvm::SmallPtrSet UseAfterReleasesTy; + typedef llvm::SmallPtrSet ReleasesNotOwnedTy; + + class BindingsPrinter : public ValueState::CheckerStatePrinter { + public: + virtual void PrintCheckerState(std::ostream& Out, void* State, + const char* nl, const char* sep); + }; + + // Instance variables. + + CFRefSummaryManager Summaries; + RefBFactoryTy RefBFactory; + + UseAfterReleasesTy UseAfterReleases; + ReleasesNotOwnedTy ReleasesNotOwned; + + BindingsPrinter Printer; + + // Private methods. + + static RefBindings GetRefBindings(ValueState& StImpl) { + return RefBindings((RefBindings::TreeTy*) StImpl.CheckerState); + } + + static void SetRefBindings(ValueState& StImpl, RefBindings B) { + StImpl.CheckerState = B.getRoot(); + } + + RefBindings Remove(RefBindings B, SymbolID sym) { + return RefBFactory.Remove(B, sym); + } + + RefBindings Update(RefBindings B, SymbolID sym, RefVal V, ArgEffect E, + RefVal::Kind& hasError); + + +public: + CFRefCount() {} + virtual ~CFRefCount() {} + + virtual ValueState::CheckerStatePrinter* getCheckerStatePrinter() { + return &Printer; + } + + // Calls. + + virtual void EvalCall(ExplodedNodeSet& Dst, + GRExprEngine& Eng, + GRStmtNodeBuilder& Builder, + CallExpr* CE, LVal L, + ExplodedNode* Pred); +}; + +} // end anonymous namespace + +void CFRefCount::BindingsPrinter::PrintCheckerState(std::ostream& Out, + void* State, const char* nl, + const char* sep) { + RefBindings B((RefBindings::TreeTy*) State); + + if (State) + Out << sep << nl; + + for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) { + Out << (*I).first << " : "; + (*I).second.print(Out); + Out << nl; + } +} + +void CFRefCount::EvalCall(ExplodedNodeSet& Dst, + GRExprEngine& Eng, + GRStmtNodeBuilder& Builder, + CallExpr* CE, LVal L, + ExplodedNode* Pred) { + + ValueStateManager& StateMgr = Eng.getStateManager(); + + // FIXME: Support calls to things other than lval::FuncVal. At the very + // least we should stop tracking ref-state for ref-counted objects passed + // to these functions. + + assert (isa(L) && "Not yet implemented."); + + // Get the summary. + + lval::FuncVal FV = cast(L); + FunctionDecl* FD = FV.getDecl(); + CFRefSummary* Summ = Summaries.getSummary(FD, Eng.getContext()); + + // Get the state. + + ValueState* St = Builder.GetState(Pred); + + // Evaluate the effects of the call. + + ValueState StVals = *St; + RefVal::Kind hasError = (RefVal::Kind) 0; + + if (!Summ) { + + // This function has no summary. Invalidate all reference-count state + // for arguments passed to this function, and also nuke the values of + // arguments passed-by-reference. + + ValueState StVals = *St; + + for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + + RVal V = StateMgr.GetRVal(St, *I); + + if (isa(V)) { + SymbolID Sym = cast(V).getSymbol(); + RefBindings B = GetRefBindings(StVals); + SetRefBindings(StVals, Remove(B, Sym)); + } + + if (isa(V)) + StateMgr.Unbind(StVals, cast(V)); + } + + St = StateMgr.getPersistentState(StVals); + + // Make up a symbol for the return value of this function. + + if (CE->getType() != Eng.getContext().VoidTy) { + unsigned Count = Builder.getCurrentBlockCount(); + SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); + + RVal X = CE->getType()->isPointerType() + ? cast(lval::SymbolVal(Sym)) + : cast(nonlval::SymbolVal(Sym)); + + St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false); + } + + Builder.Nodify(Dst, CE, Pred, St); + return; + } + + // This function has a summary. Evaluate the effect of the arguments. + + unsigned idx = 0; + + for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); + I!=E; ++I, ++idx) { + + RVal V = StateMgr.GetRVal(St, *I); + + if (isa(V)) { + SymbolID Sym = cast(V).getSymbol(); + RefBindings B = GetRefBindings(StVals); + + if (RefBindings::TreeTy* T = B.SlimFind(Sym)) { + B = Update(B, Sym, T->getValue().second, Summ->getArg(idx), hasError); + SetRefBindings(StVals, B); + if (hasError) break; + } + } + } + + if (hasError) { + St = StateMgr.getPersistentState(StVals); + GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred); + + if (N) { + N->markAsSink(); + + switch (hasError) { + default: assert(false); + case RefVal::ErrorUseAfterRelease: + UseAfterReleases.insert(N); + break; + + case RefVal::ErrorReleaseNotOwned: + ReleasesNotOwned.insert(N); + break; + } + } + + return; + } + + // Finally, consult the summary for the return value. + + RetEffect RE = Summ->getRet(); + St = StateMgr.getPersistentState(StVals); + + + switch (RE.getKind()) { + default: + assert (false && "Unhandled RetEffect."); break; + + case RetEffect::Alias: { + unsigned idx = RE.getValue(); + assert (idx < CE->getNumArgs()); + RVal V = StateMgr.GetRVal(St, CE->getArg(idx)); + St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false); + break; + } + + case RetEffect::OwnedSymbol: { + unsigned Count = Builder.getCurrentBlockCount(); + SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); + + ValueState StImpl = *St; + RefBindings B = GetRefBindings(StImpl); + SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned(1))); + + St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), + CE, lval::SymbolVal(Sym), + Eng.getCFG().isBlkExpr(CE), false); + + break; + } + + case RetEffect::NotOwnedSymbol: { + unsigned Count = Builder.getCurrentBlockCount(); + SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); + + ValueState StImpl = *St; + RefBindings B = GetRefBindings(StImpl); + SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned())); + + St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl), + CE, lval::SymbolVal(Sym), + Eng.getCFG().isBlkExpr(CE), false); + + break; + } + } + + Builder.Nodify(Dst, CE, Pred, St); +} + + +CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym, + RefVal V, ArgEffect E, + RefVal::Kind& hasError) { + + // FIXME: This dispatch can potentially be sped up by unifiying it into + // a single switch statement. Opt for simplicity for now. + + switch (E) { + default: + assert (false && "Unhandled CFRef transition."); + + case DoNothing: + if (V.getKind() == RefVal::Released) { + V = RefVal::makeUseAfterRelease(); + hasError = V.getKind(); + break; + } + + return B; + + case IncRef: + switch (V.getKind()) { + default: + assert(false); + + case RefVal::Owned: + V = RefVal::makeOwned(V.getCount()+1); break; + + case RefVal::AcqOwned: + V = RefVal::makeAcqOwned(V.getCount()+1); + break; + + case RefVal::NotOwned: + V = RefVal::makeAcqOwned(1); + break; + + case RefVal::Released: + V = RefVal::makeUseAfterRelease(); + hasError = V.getKind(); + break; + } + + case DecRef: + switch (V.getKind()) { + default: + assert (false); + + case RefVal::Owned: { + unsigned Count = V.getCount() - 1; + V = Count ? RefVal::makeOwned(Count) : RefVal::makeReleased(); + break; + } + + case RefVal::AcqOwned: { + unsigned Count = V.getCount() - 1; + V = Count ? RefVal::makeAcqOwned(Count) : RefVal::makeNotOwned(); + break; + } + + case RefVal::NotOwned: + V = RefVal::makeReleaseNotOwned(); + hasError = V.getKind(); + break; + + case RefVal::Released: + V = RefVal::makeUseAfterRelease(); + hasError = V.getKind(); + break; + } + } + + return RefBFactory.Add(B, sym, V); +} + +//===----------------------------------------------------------------------===// +// Driver for the CFRefCount Checker. +//===----------------------------------------------------------------------===// + +namespace clang { + + void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx, + Diagnostic& Diag) { + + if (Diag.hasErrorOccurred()) + return; + + // FIXME: Refactor some day so this becomes a single function invocation. + + GRCoreEngine Eng(cfg, CD, Ctx); + GRExprEngine* CS = &Eng.getCheckerState(); + CFRefCount TF; + CS->setTransferFunctions(TF); + Eng.ExecuteWorkList(20000); + + } + +} // end clang namespace diff --git a/clang/lib/Analysis/DeadStores.cpp b/clang/lib/Analysis/DeadStores.cpp new file mode 100644 index 00000000000..0848336e586 --- /dev/null +++ b/clang/lib/Analysis/DeadStores.cpp @@ -0,0 +1,87 @@ +//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a DeadStores, a flow-sensitive checker that looks for +// stores to variables that are no longer live. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/LocalCheckers.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +namespace { + +class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy { + ASTContext &Ctx; + Diagnostic &Diags; +public: + DeadStoreObs(ASTContext &ctx,Diagnostic &diags) : Ctx(ctx), Diags(diags){} + virtual ~DeadStoreObs() {} + + virtual void ObserveStmt(Stmt* S, + const LiveVariables::AnalysisDataTy& AD, + const LiveVariables::ValTy& Live) { + + if (BinaryOperator* B = dyn_cast(S)) { + if (!B->isAssignmentOp()) return; // Skip non-assignments. + + if (DeclRefExpr* DR = dyn_cast(B->getLHS())) + if (VarDecl* VD = dyn_cast(DR->getDecl())) + if (VD->hasLocalStorage() && !Live(VD,AD)) { + SourceRange R = B->getRHS()->getSourceRange(); + Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), + diag::warn_dead_store, 0, 0, &R, 1); + } + } + else if(DeclStmt* DS = dyn_cast(S)) + // Iterate through the decls. Warn if any initializers are complex + // expressions that are not live (never used). + for (VarDecl* V = cast(DS->getDecl()); V != NULL ; + V = cast_or_null(V->getNextDeclarator())) { + if (V->hasLocalStorage()) + if (Expr* E = V->getInit()) { + if (!Live(DS->getDecl(),AD)) { + // Special case: check for initializations with constants. + // + // e.g. : int x = 0; + // + // If x is EVER assigned a new value later, don't issue + // a warning. This is because such initialization can be + // due to defensive programming. + if (!E->isConstantExpr(Ctx,NULL)) { + // Flag a warning. + SourceRange R = E->getSourceRange(); + Diags.Report(Ctx.getFullLoc(V->getLocation()), + diag::warn_dead_store, 0, 0, &R, 1); + } + } + } + } + } +}; + +} // end anonymous namespace + +namespace clang { + +void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) { + + LiveVariables L(cfg); + L.runOnCFG(cfg); + DeadStoreObs A(Ctx, Diags); + L.runOnAllBlocks(cfg, &A); +} + +} // end namespace clang diff --git a/clang/lib/Analysis/ExplodedGraph.cpp b/clang/lib/Analysis/ExplodedGraph.cpp new file mode 100644 index 00000000000..2ba46d77d63 --- /dev/null +++ b/clang/lib/Analysis/ExplodedGraph.cpp @@ -0,0 +1,227 @@ +//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph, +// which represent a path-sensitive, intra-procedural "exploded graph." +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/ExplodedGraph.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include +#include + +using namespace clang; + + +static inline std::vector& getVector(void* P) { + return *reinterpret_cast*>(P); +} + +void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) { + + assert ((reinterpret_cast(N) & Mask) == 0x0); + assert (!getFlag()); + + if (getKind() == Size1) { + if (ExplodedNodeImpl* NOld = getNode()) { + std::vector* V = new std::vector(); + assert ((reinterpret_cast(V) & Mask) == 0x0); + V->push_back(NOld); + V->push_back(N); + P = reinterpret_cast(V) | SizeOther; + assert (getPtr() == (void*) V); + assert (getKind() == SizeOther); + } + else { + P = reinterpret_cast(N); + assert (getKind() == Size1); + } + } + else { + assert (getKind() == SizeOther); + getVector(getPtr()).push_back(N); + } +} + + +unsigned ExplodedNodeImpl::NodeGroup::size() const { + if (getFlag()) + return 0; + + if (getKind() == Size1) + return getNode() ? 1 : 0; + else + return getVector(getPtr()).size(); +} + +ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const { + if (getFlag()) + return NULL; + + if (getKind() == Size1) + return (ExplodedNodeImpl**) (getPtr() ? &P : NULL); + else + return const_cast(&*(getVector(getPtr()).begin())); +} + +ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const { + if (getFlag()) + return NULL; + + if (getKind() == Size1) + return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL); + else + return const_cast(&*(getVector(getPtr()).end())); +} + +ExplodedNodeImpl::NodeGroup::~NodeGroup() { + if (getKind() == SizeOther) delete &getVector(getPtr()); +} + +ExplodedGraphImpl* ExplodedGraphImpl::Trim(ExplodedNodeImpl** BeginSources, + ExplodedNodeImpl** EndSources) const{ + + typedef llvm::DenseMap Pass1Ty; + typedef llvm::DenseMap Pass2Ty; + + Pass1Ty Pass1; + Pass2Ty Pass2; + + llvm::SmallVector WL2; + + { // ===- Pass 1 (reverse BFS) -=== + + // Enqueue the source nodes to the first worklist. + + std::list > WL1; + + for (ExplodedNodeImpl** I = BeginSources; I != EndSources; ++I) + WL1.push_back(std::make_pair(*I, *I)); + + // Process the worklist. + + while (!WL1.empty()) { + + ExplodedNodeImpl* N = WL1.back().first; + ExplodedNodeImpl* Src = WL1.back().second; + + WL1.pop_back(); + + if (Pass1.find(N) != Pass1.end()) + continue; + + bool PredHasSameSource = false; + bool VisitPreds = true; + + for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); + I!=E; ++I) { + + Pass1Ty::iterator pi = Pass1.find(*I); + + if (pi == Pass1.end()) + continue; + + VisitPreds = false; + + if (pi->second == Src) { + PredHasSameSource = true; + break; + } + } + + if (VisitPreds || !PredHasSameSource) { + + Pass1[N] = Src; + + if (N->Preds.empty()) { + WL2.push_back(N); + continue; + } + } + else + Pass1[N] = NULL; + + if (VisitPreds) + for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); + I!=E; ++I) + WL1.push_front(std::make_pair(*I, Src)); + } + } + + if (WL2.empty()) + return NULL; + + ExplodedGraphImpl* G = MakeEmptyGraph(); + + // ===- Pass 2 (forward DFS to construct the new graph) -=== + + while (!WL2.empty()) { + + ExplodedNodeImpl* N = WL2.back(); + WL2.pop_back(); + + // Skip this node if we have already processed it. + + if (Pass2.find(N) != Pass2.end()) + continue; + + // Create the corresponding node in the new graph. + + ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL); + Pass2[N] = NewN; + + if (N->Preds.empty()) + G->addRoot(NewN); + + // In the case that some of the intended predecessors of NewN have already + // been created, we should hook them up as predecessors. + + for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) { + + Pass2Ty::iterator PI = Pass2.find(*I); + + if (PI == Pass2.end()) + continue; + + NewN->addPredecessor(PI->second); + } + + // In the case that some of the intended successors of NewN have already + // been created, we should hook them up as successors. Otherwise, enqueue + // the new nodes from the original graph that should have nodes created + // in the new graph. + + for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) { + + Pass2Ty::iterator PI = Pass2.find(*I); + + if (PI != Pass2.end()) { + PI->second->addPredecessor(NewN); + continue; + } + + // Enqueue nodes to the worklist that were marked during pass 1. + + Pass1Ty::iterator pi = Pass1.find(*I); + + if (pi == Pass1.end() || pi->second == NULL) + continue; + + WL2.push_back(*I); + } + + if (N->isSink()) + NewN->markAsSink(); + } + + return G; +} diff --git a/clang/lib/Analysis/GRBlockCounter.cpp b/clang/lib/Analysis/GRBlockCounter.cpp new file mode 100644 index 00000000000..3ecc39d3224 --- /dev/null +++ b/clang/lib/Analysis/GRBlockCounter.cpp @@ -0,0 +1,54 @@ +//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by GRCoreEngine. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/GRBlockCounter.h" +#include "llvm/ADT/ImmutableMap.h" + +using namespace clang; + +typedef llvm::ImmutableMap CountMap; + +static inline CountMap GetMap(void* D) { + return CountMap(static_cast(D)); +} + +static inline CountMap::Factory& GetFactory(void* F) { + return *static_cast(F); +} + +unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const { + CountMap M = GetMap(Data); + CountMap::TreeTy* T = M.SlimFind(BlockID); + return T ? T->getValue().second : 0; +} + +GRBlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) { + F = new CountMap::Factory(Alloc); +} + +GRBlockCounter::Factory::~Factory() { + delete static_cast(F); +} + +GRBlockCounter +GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) { + return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID, + BC.getNumVisited(BlockID)+1).getRoot()); +} + +GRBlockCounter +GRBlockCounter::Factory::GetEmptyCounter() { + return GRBlockCounter(GetFactory(F).GetEmptyMap().getRoot()); +} diff --git a/clang/lib/Analysis/GRCoreEngine.cpp b/clang/lib/Analysis/GRCoreEngine.cpp new file mode 100644 index 00000000000..53831ed06d5 --- /dev/null +++ b/clang/lib/Analysis/GRCoreEngine.cpp @@ -0,0 +1,444 @@ +//==- GRCoreEngine.cpp - Path-Sensitive Dataflow 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 a generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability engine. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/GRCoreEngine.h" +#include "clang/AST/Expr.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/DenseMap.h" +#include + +using llvm::cast; +using llvm::isa; +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN DFS : public GRWorkList { + llvm::SmallVector Stack; +public: + virtual bool hasWork() const { + return !Stack.empty(); + } + + virtual void Enqueue(const GRWorkListUnit& U) { + Stack.push_back(U); + } + + virtual GRWorkListUnit Dequeue() { + assert (!Stack.empty()); + const GRWorkListUnit& U = Stack.back(); + Stack.pop_back(); // This technically "invalidates" U, but we are fine. + return U; + } +}; +} // end anonymous namespace + +// Place the dstor for GRWorkList here because it contains virtual member +// functions, and we the code for the dstor generated in one compilation unit. +GRWorkList::~GRWorkList() {} + +GRWorkList* GRWorkList::MakeDFS() { return new DFS(); } + +/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. +bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { + + if (G->num_roots() == 0) { // Initialize the analysis by constructing + // the root if none exists. + + CFGBlock* Entry = &getCFG().getEntry(); + + assert (Entry->empty() && + "Entry block must be empty."); + + assert (Entry->succ_size() == 1 && + "Entry block must have 1 successor."); + + // Get the solitary successor. + CFGBlock* Succ = *(Entry->succ_begin()); + + // Construct an edge representing the + // starting location in the function. + BlockEdge StartLoc(getCFG(), Entry, Succ); + + // Set the current block counter to being empty. + WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); + + // Generate the root. + GenerateNode(StartLoc, getInitialState()); + } + + while (Steps && WList->hasWork()) { + --Steps; + const GRWorkListUnit& WU = WList->Dequeue(); + + // Set the current block counter. + WList->setBlockCounter(WU.getBlockCounter()); + + // Retrieve the node. + ExplodedNodeImpl* Node = WU.getNode(); + + // Dispatch on the location type. + switch (Node->getLocation().getKind()) { + default: + assert (isa(Node->getLocation())); + HandleBlockEdge(cast(Node->getLocation()), Node); + break; + + case ProgramPoint::BlockEntranceKind: + HandleBlockEntrance(cast(Node->getLocation()), Node); + break; + + case ProgramPoint::BlockExitKind: + assert (false && "BlockExit location never occur in forward analysis."); + break; + + case ProgramPoint::PostStmtKind: + HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), + WU.getIndex(), Node); + break; + } + } + + return WList->hasWork(); +} + +void GRCoreEngineImpl::HandleBlockEdge(const BlockEdge& L, + ExplodedNodeImpl* Pred) { + + CFGBlock* Blk = L.getDst(); + + // Check if we are entering the EXIT block. + if (Blk == &getCFG().getExit()) { + + assert (getCFG().getExit().size() == 0 + && "EXIT block cannot contain Stmts."); + + // Process the final state transition. + void* State = ProcessEOP(Blk, Pred->State); + + bool IsNew; + ExplodedNodeImpl* Node = G->getNodeImpl(BlockEntrance(Blk), State, &IsNew); + Node->addPredecessor(Pred); + + // If the node was freshly created, mark it as an "End-Of-Path" node. + if (IsNew) G->addEndOfPath(Node); + + // This path is done. Don't enqueue any more nodes. + return; + } + + // FIXME: Should we allow ProcessBlockEntrance to also manipulate state? + + if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter())) + GenerateNode(BlockEntrance(Blk), Pred->State, Pred); +} + +void GRCoreEngineImpl::HandleBlockEntrance(const BlockEntrance& L, + ExplodedNodeImpl* Pred) { + + // Increment the block counter. + GRBlockCounter Counter = WList->getBlockCounter(); + Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID()); + WList->setBlockCounter(Counter); + + // Process the entrance of the block. + if (Stmt* S = L.getFirstStmt()) { + GRStmtNodeBuilderImpl Builder(L.getBlock(), 0, Pred, this); + ProcessStmt(S, Builder); + } + else + HandleBlockExit(L.getBlock(), Pred); +} + + +void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) { + + if (Stmt* Term = B->getTerminator()) { + switch (Term->getStmtClass()) { + default: + assert(false && "Analysis for this terminator not implemented."); + break; + + case Stmt::BinaryOperatorClass: // '&&' and '||' + HandleBranch(cast(Term)->getLHS(), Term, B, Pred); + return; + + case Stmt::ConditionalOperatorClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + // FIXME: Use constant-folding in CFG construction to simplify this + // case. + + case Stmt::ChooseExprClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::DoStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::ForStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::ContinueStmtClass: + case Stmt::BreakStmtClass: + case Stmt::GotoStmtClass: + break; + + case Stmt::IfStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + + case Stmt::IndirectGotoStmtClass: { + // Only 1 successor: the indirect goto dispatch block. + assert (B->succ_size() == 1); + + GRIndirectGotoNodeBuilderImpl + builder(Pred, B, cast(Term)->getTarget(), + *(B->succ_begin()), this); + + ProcessIndirectGoto(builder); + return; + } + + case Stmt::SwitchStmtClass: { + GRSwitchNodeBuilderImpl builder(Pred, B, + cast(Term)->getCond(), + this); + + ProcessSwitch(builder); + return; + } + + case Stmt::WhileStmtClass: + HandleBranch(cast(Term)->getCond(), Term, B, Pred); + return; + } + } + + assert (B->succ_size() == 1 && + "Blocks with no terminator should have at most 1 successor."); + + GenerateNode(BlockEdge(getCFG(),B,*(B->succ_begin())), Pred->State, Pred); +} + +void GRCoreEngineImpl::HandleBranch(Expr* Cond, Stmt* Term, CFGBlock * B, + ExplodedNodeImpl* Pred) { + assert (B->succ_size() == 2); + + GRBranchNodeBuilderImpl Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), + Pred, this); + + ProcessBranch(Cond, Term, Builder); +} + +void GRCoreEngineImpl::HandlePostStmt(const PostStmt& L, CFGBlock* B, + unsigned StmtIdx, ExplodedNodeImpl* Pred) { + + assert (!B->empty()); + + if (StmtIdx == B->size()) + HandleBlockExit(B, Pred); + else { + GRStmtNodeBuilderImpl Builder(B, StmtIdx, Pred, this); + ProcessStmt((*B)[StmtIdx], Builder); + } +} + +typedef llvm::DenseMap ParentMapTy; +/// PopulateParentMap - Recurse the AST starting at 'Parent' and add the +/// mappings between child and parent to ParentMap. +static void PopulateParentMap(Stmt* Parent, ParentMapTy& M) { + for (Stmt::child_iterator I=Parent->child_begin(), + E=Parent->child_end(); I!=E; ++I) { + + assert (M.find(*I) == M.end()); + M[*I] = Parent; + PopulateParentMap(*I, M); + } +} + +/// GenerateNode - Utility method to generate nodes, hook up successors, +/// and add nodes to the worklist. +void GRCoreEngineImpl::GenerateNode(const ProgramPoint& Loc, void* State, + ExplodedNodeImpl* Pred) { + + bool IsNew; + ExplodedNodeImpl* Node = G->getNodeImpl(Loc, State, &IsNew); + + if (Pred) + Node->addPredecessor(Pred); // Link 'Node' with its predecessor. + else { + assert (IsNew); + G->addRoot(Node); // 'Node' has no predecessor. Make it a root. + } + + // Only add 'Node' to the worklist if it was freshly generated. + if (IsNew) WList->Enqueue(Node); +} + +GRStmtNodeBuilderImpl::GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx, + ExplodedNodeImpl* N, GRCoreEngineImpl* e) + : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Populated(false) { + Deferred.insert(N); +} + +GRStmtNodeBuilderImpl::~GRStmtNodeBuilderImpl() { + for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) + if (!(*I)->isSink()) + GenerateAutoTransition(*I); +} + +void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) { + assert (!N->isSink()); + + PostStmt Loc(getStmt()); + + if (Loc == N->getLocation()) { + // Note: 'N' should be a fresh node because otherwise it shouldn't be + // a member of Deferred. + Eng.WList->Enqueue(N, B, Idx+1); + return; + } + + bool IsNew; + ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(Loc, N->State, &IsNew); + Succ->addPredecessor(N); + + if (IsNew) + Eng.WList->Enqueue(Succ, B, Idx+1); +} + +ExplodedNodeImpl* GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State, + ExplodedNodeImpl* Pred) { + + bool IsNew; + ExplodedNodeImpl* N = Eng.G->getNodeImpl(PostStmt(S), State, &IsNew); + N->addPredecessor(Pred); + Deferred.erase(Pred); + + HasGeneratedNode = true; + + if (IsNew) { + Deferred.insert(N); + LastNode = N; + return N; + } + + LastNode = NULL; + return NULL; +} + +ExplodedNodeImpl* GRBranchNodeBuilderImpl::generateNodeImpl(void* State, + bool branch) { + bool IsNew; + + ExplodedNodeImpl* Succ = + Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, branch ? DstT : DstF), + State, &IsNew); + + Succ->addPredecessor(Pred); + + if (branch) GeneratedTrue = true; + else GeneratedFalse = true; + + if (IsNew) { + Deferred.push_back(Succ); + return Succ; + } + + return NULL; +} + +GRBranchNodeBuilderImpl::~GRBranchNodeBuilderImpl() { + if (!GeneratedTrue) generateNodeImpl(Pred->State, true); + if (!GeneratedFalse) generateNodeImpl(Pred->State, false); + + for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I) + if (!(*I)->isSink()) Eng.WList->Enqueue(*I); +} + + +ExplodedNodeImpl* +GRIndirectGotoNodeBuilderImpl::generateNodeImpl(const Iterator& I, + void* St, + bool isSink) { + bool IsNew; + + ExplodedNodeImpl* Succ = + Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, I.getBlock(), true), + St, &IsNew); + + Succ->addPredecessor(Pred); + + if (IsNew) { + + if (isSink) + Succ->markAsSink(); + else + Eng.WList->Enqueue(Succ); + + return Succ; + } + + return NULL; +} + + +ExplodedNodeImpl* +GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I, void* St) { + + bool IsNew; + + ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, + I.getBlock()), + St, &IsNew); + Succ->addPredecessor(Pred); + + if (IsNew) { + Eng.WList->Enqueue(Succ); + return Succ; + } + + return NULL; +} + + +ExplodedNodeImpl* +GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(void* St, bool isSink) { + + // Get the block for the default case. + assert (Src->succ_rbegin() != Src->succ_rend()); + CFGBlock* DefaultBlock = *Src->succ_rbegin(); + + bool IsNew; + + ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, + DefaultBlock), + St, &IsNew); + Succ->addPredecessor(Pred); + + if (IsNew) { + if (isSink) + Succ->markAsSink(); + else + Eng.WList->Enqueue(Succ); + + return Succ; + } + + return NULL; +} diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp new file mode 100644 index 00000000000..f1108df4051 --- /dev/null +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -0,0 +1,1941 @@ +//=-- GRExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a meta-engine for path-sensitive dataflow analysis that +// is built on GREngine, but provides the boilerplate to execute transfer +// functions and build the ExplodedGraph at the expression level. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/Streams.h" + +#ifndef NDEBUG +#include "llvm/Support/GraphWriter.h" +#include +#endif + +// SaveAndRestore - A utility class that uses RIIA to save and restore +// the value of a variable. +template +struct VISIBILITY_HIDDEN SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } + + T& X; + T old_value; +}; + +using namespace clang; +using llvm::dyn_cast; +using llvm::cast; +using llvm::APSInt; + + +ValueState* GRExprEngine::getInitialState() { + + // The LiveVariables information already has a compilation of all VarDecls + // used in the function. Iterate through this set, and "symbolicate" + // any VarDecl whose value originally comes from outside the function. + + typedef LiveVariables::AnalysisDataTy LVDataTy; + LVDataTy& D = Liveness.getAnalysisData(); + + ValueState StateImpl = *StateMgr.getInitialState(); + + for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) { + + VarDecl* VD = cast(const_cast(I->first)); + + if (VD->hasGlobalStorage() || isa(VD)) { + RVal X = RVal::GetSymbolValue(SymMgr, VD); + StateMgr.BindVar(StateImpl, VD, X); + } + } + + return StateMgr.getPersistentState(StateImpl); +} + +ValueState* GRExprEngine::SetRVal(ValueState* St, Expr* Ex, RVal V) { + + bool isBlkExpr = false; + + if (Ex == CurrentStmt) { + isBlkExpr = getCFG().isBlkExpr(Ex); + + if (!isBlkExpr) + return St; + } + + return StateMgr.SetRVal(St, Ex, V, isBlkExpr, false); +} + +ValueState* GRExprEngine::MarkBranch(ValueState* St, Stmt* Terminator, + bool branchTaken) { + + switch (Terminator->getStmtClass()) { + default: + return St; + + case Stmt::BinaryOperatorClass: { // '&&' and '||' + + BinaryOperator* B = cast(Terminator); + BinaryOperator::Opcode Op = B->getOpcode(); + + assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr); + + // For &&, if we take the true branch, then the value of the whole + // expression is that of the RHS expression. + // + // For ||, if we take the false branch, then the value of the whole + // expression is that of the RHS expression. + + Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) || + (Op == BinaryOperator::LOr && !branchTaken) + ? B->getRHS() : B->getLHS(); + + return SetBlkExprRVal(St, B, UndefinedVal(Ex)); + } + + case Stmt::ConditionalOperatorClass: { // ?: + + ConditionalOperator* C = cast(Terminator); + + // For ?, if branchTaken == true then the value is either the LHS or + // the condition itself. (GNU extension). + + Expr* Ex; + + if (branchTaken) + Ex = C->getLHS() ? C->getLHS() : C->getCond(); + else + Ex = C->getRHS(); + + return SetBlkExprRVal(St, C, UndefinedVal(Ex)); + } + + case Stmt::ChooseExprClass: { // ?: + + ChooseExpr* C = cast(Terminator); + + Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); + return SetBlkExprRVal(St, C, UndefinedVal(Ex)); + } + } +} + +bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, ValueState*, + GRBlockCounter BC) { + + return BC.getNumVisited(B->getBlockID()) < 3; +} + +void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term, + BranchNodeBuilder& builder) { + + // Remove old bindings for subexpressions. + ValueState* PrevState = StateMgr.RemoveSubExprBindings(builder.getState()); + + // Check for NULL conditions; e.g. "for(;;)" + if (!Condition) { + builder.markInfeasible(false); + return; + } + + RVal V = GetRVal(PrevState, Condition); + + switch (V.getBaseKind()) { + default: + break; + + case RVal::UnknownKind: + builder.generateNode(MarkBranch(PrevState, Term, true), true); + builder.generateNode(MarkBranch(PrevState, Term, false), false); + return; + + case RVal::UndefinedKind: { + NodeTy* N = builder.generateNode(PrevState, true); + + if (N) { + N->markAsSink(); + UndefBranches.insert(N); + } + + builder.markInfeasible(false); + return; + } + } + + + // Process the true branch. + + bool isFeasible = false; + ValueState* St = Assume(PrevState, V, true, isFeasible); + + if (isFeasible) + builder.generateNode(MarkBranch(St, Term, true), true); + else + builder.markInfeasible(true); + + // Process the false branch. + + isFeasible = false; + St = Assume(PrevState, V, false, isFeasible); + + if (isFeasible) + builder.generateNode(MarkBranch(St, Term, false), false); + else + builder.markInfeasible(false); +} + +/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor +/// nodes by processing the 'effects' of a computed goto jump. +void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) { + + ValueState* St = builder.getState(); + RVal V = GetRVal(St, builder.getTarget()); + + // Three possibilities: + // + // (1) We know the computed label. + // (2) The label is NULL (or some other constant), or Undefined. + // (3) We have no clue about the label. Dispatch to all targets. + // + + typedef IndirectGotoNodeBuilder::iterator iterator; + + if (isa(V)) { + LabelStmt* L = cast(V).getLabel(); + + for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) { + if (I.getLabel() == L) { + builder.generateNode(I, St); + return; + } + } + + assert (false && "No block with label."); + return; + } + + if (isa(V) || isa(V)) { + // Dispatch to the first target and mark it as a sink. + NodeTy* N = builder.generateNode(builder.begin(), St, true); + UndefBranches.insert(N); + return; + } + + // This is really a catch-all. We don't support symbolics yet. + + assert (V.isUnknown()); + + for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) + builder.generateNode(I, St); +} + +/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor +/// nodes by processing the 'effects' of a switch statement. +void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { + + typedef SwitchNodeBuilder::iterator iterator; + + ValueState* St = builder.getState(); + Expr* CondE = builder.getCondition(); + RVal CondV = GetRVal(St, CondE); + + if (CondV.isUndef()) { + NodeTy* N = builder.generateDefaultCaseNode(St, true); + UndefBranches.insert(N); + return; + } + + ValueState* DefaultSt = St; + + // While most of this can be assumed (such as the signedness), having it + // just computed makes sure everything makes the same assumptions end-to-end. + + unsigned bits = getContext().getTypeSize(CondE->getType()); + + APSInt V1(bits, false); + APSInt V2 = V1; + + for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) { + + CaseStmt* Case = cast(I.getCase()); + + // Evaluate the case. + if (!Case->getLHS()->isIntegerConstantExpr(V1, getContext(), 0, true)) { + assert (false && "Case condition must evaluate to an integer constant."); + return; + } + + // Get the RHS of the case, if it exists. + + if (Expr* E = Case->getRHS()) { + if (!E->isIntegerConstantExpr(V2, getContext(), 0, true)) { + assert (false && + "Case condition (RHS) must evaluate to an integer constant."); + return ; + } + + assert (V1 <= V2); + } + else V2 = V1; + + // FIXME: Eventually we should replace the logic below with a range + // comparison, rather than concretize the values within the range. + // This should be easy once we have "ranges" for NonLVals. + + do { + nonlval::ConcreteInt CaseVal(BasicVals.getValue(V1)); + + RVal Res = EvalBinOp(BinaryOperator::EQ, CondV, CaseVal); + + // Now "assume" that the case matches. + + bool isFeasible = false; + ValueState* StNew = Assume(St, Res, true, isFeasible); + + if (isFeasible) { + builder.generateCaseStmtNode(I, StNew); + + // If CondV evaluates to a constant, then we know that this + // is the *only* case that we can take, so stop evaluating the + // others. + if (isa(CondV)) + return; + } + + // Now "assume" that the case doesn't match. Add this state + // to the default state (if it is feasible). + + isFeasible = false; + StNew = Assume(DefaultSt, Res, false, isFeasible); + + if (isFeasible) + DefaultSt = StNew; + + // Concretize the next value in the range. + ++V1; + + } while (V1 < V2); + } + + // If we reach here, than we know that the default branch is + // possible. + builder.generateDefaultCaseNode(DefaultSt); +} + + +void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, + NodeSet& Dst) { + + assert (B->getOpcode() == BinaryOperator::LAnd || + B->getOpcode() == BinaryOperator::LOr); + + assert (B == CurrentStmt && getCFG().isBlkExpr(B)); + + ValueState* St = GetState(Pred); + RVal X = GetBlkExprRVal(St, B); + + assert (X.isUndef()); + + Expr* Ex = (Expr*) cast(X).getData(); + + assert (Ex); + + if (Ex == B->getRHS()) { + + X = GetBlkExprRVal(St, Ex); + + // Handle undefined values. + + if (X.isUndef()) { + Nodify(Dst, B, Pred, SetBlkExprRVal(St, B, X)); + return; + } + + // We took the RHS. Because the value of the '&&' or '||' expression must + // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0 + // or 1. Alternatively, we could take a lazy approach, and calculate this + // value later when necessary. We don't have the machinery in place for + // this right now, and since most logical expressions are used for branches, + // the payoff is not likely to be large. Instead, we do eager evaluation. + + bool isFeasible = false; + ValueState* NewState = Assume(St, X, true, isFeasible); + + if (isFeasible) + Nodify(Dst, B, Pred, SetBlkExprRVal(NewState, B, MakeConstantVal(1U, B))); + + isFeasible = false; + NewState = Assume(St, X, false, isFeasible); + + if (isFeasible) + Nodify(Dst, B, Pred, SetBlkExprRVal(NewState, B, MakeConstantVal(0U, B))); + } + else { + // We took the LHS expression. Depending on whether we are '&&' or + // '||' we know what the value of the expression is via properties of + // the short-circuiting. + + X = MakeConstantVal( B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, B); + Nodify(Dst, B, Pred, SetBlkExprRVal(St, B, X)); + } +} + + +void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { + + Builder = &builder; + StmtEntryNode = builder.getLastNode(); + CurrentStmt = S; + NodeSet Dst; + + // Create the cleaned state. + + CleanedState = StateMgr.RemoveDeadBindings(StmtEntryNode->getState(), + CurrentStmt, Liveness); + + Builder->SetCleanedState(CleanedState); + + // Visit the statement. + + Visit(S, StmtEntryNode, Dst); + + // If no nodes were generated, generate a new node that has all the + // dead mappings removed. + + if (Dst.size() == 1 && *Dst.begin() == StmtEntryNode) + builder.generateNode(S, GetState(StmtEntryNode), StmtEntryNode); + + // NULL out these variables to cleanup. + + CurrentStmt = NULL; + StmtEntryNode = NULL; + Builder = NULL; + CleanedState = NULL; +} + +void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ + + if (D != CurrentStmt) { + Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. + return; + } + + // If we are here, we are loading the value of the decl and binding + // it to the block-level expression. + + ValueState* St = GetState(Pred); + RVal X = RVal::MakeVal(BasicVals, D); + RVal Y = isa(X) ? GetRVal(St, cast(X)) : X; + Nodify(Dst, D, Pred, SetBlkExprRVal(St, D, Y)); +} + +void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator AI, + CallExpr::arg_iterator AE, + NodeSet& Dst) { + + // Process the arguments. + + if (AI != AE) { + + NodeSet DstTmp; + Visit(*AI, Pred, DstTmp); + ++AI; + + for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI) + VisitCall(CE, *DI, AI, AE, Dst); + + return; + } + + // If we reach here we have processed all of the arguments. Evaluate + // the callee expression. + + NodeSet DstTmp; + Expr* Callee = CE->getCallee()->IgnoreParenCasts(); + + VisitLVal(Callee, Pred, DstTmp); + + if (DstTmp.empty()) + DstTmp.Add(Pred); + + // Finally, evaluate the function call. + for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { + + ValueState* St = GetState(*DI); + RVal L = GetLVal(St, Callee); + + // FIXME: Add support for symbolic function calls (calls involving + // function pointer values that are symbolic). + + // Check for undefined control-flow or calls to NULL. + + if (L.isUndef() || isa(L)) { + NodeTy* N = Builder->generateNode(CE, St, *DI); + + if (N) { + N->markAsSink(); + BadCalls.insert(N); + } + + continue; + } + + // Check for the "noreturn" attribute. + + SaveAndRestore OldSink(Builder->BuildSinks); + + if (isa(L)) { + + FunctionDecl* FD = cast(L).getDecl(); + + if (FD->getAttr()) + Builder->BuildSinks = true; + else { + // HACK: Some functions are not marked noreturn, and don't return. + // Here are a few hardwired ones. If this takes too long, we can + // potentially cache these results. + const char* s = FD->getIdentifier()->getName(); + unsigned n = strlen(s); + + switch (n) { + default: + break; + + case 4: + if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true; + break; + + case 5: + if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true; + break; + } + } + } + + // Evaluate the call. + + + bool invalidateArgs = false; + + if (L.isUnknown()) { + // Check for an "unknown" callee. + invalidateArgs = true; + } + else if (isa(L)) { + + IdentifierInfo* Info = cast(L).getDecl()->getIdentifier(); + + if (unsigned id = Info->getBuiltinID()) { + switch (id) { + case Builtin::BI__builtin_expect: { + // For __builtin_expect, just return the value of the subexpression. + assert (CE->arg_begin() != CE->arg_end()); + RVal X = GetRVal(St, *(CE->arg_begin())); + Nodify(Dst, CE, *DI, SetRVal(St, CE, X)); + continue; + } + + default: + invalidateArgs = true; + break; + } + } + } + + if (invalidateArgs) { + // Invalidate all arguments passed in by reference (LVals). + for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + RVal V = GetRVal(St, *I); + + if (isa(V)) + St = SetRVal(St, cast(V), UnknownVal()); + } + + Nodify(Dst, CE, *DI, St); + } + else { + + // Check any arguments passed-by-value against being undefined. + + bool badArg = false; + + for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + + if (GetRVal(GetState(*DI), *I).isUndef()) { + NodeTy* N = Builder->generateNode(CE, GetState(*DI), *DI); + + if (N) { + N->markAsSink(); + UndefArgs[N] = *I; + } + + badArg = true; + break; + } + } + + if (badArg) + continue; + + // Dispatch to the plug-in transfer function. + + unsigned size = Dst.size(); + + EvalCall(Dst, CE, cast(L), *DI); + + if (!Builder->BuildSinks && Dst.size() == size) + Nodify(Dst, CE, *DI, St); + } + } +} + +void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ + + NodeSet S1; + QualType T = CastE->getType(); + + if (T->isReferenceType()) + VisitLVal(Ex, Pred, S1); + else + Visit(Ex, Pred, S1); + + // Check for redundant casts or casting to "void" + if (T->isVoidType() || + Ex->getType() == T || + (T->isPointerType() && Ex->getType()->isFunctionType())) { + + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) + Dst.Add(*I1); + + return; + } + + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { + NodeTy* N = *I1; + ValueState* St = GetState(N); + + RVal V = T->isReferenceType() ? GetLVal(St, Ex) : GetRVal(St, Ex); + + Nodify(Dst, CastE, N, SetRVal(St, CastE, EvalCast(V, CastE->getType()))); + } +} + +void GRExprEngine::VisitDeclStmt(DeclStmt* DS, GRExprEngine::NodeTy* Pred, + GRExprEngine::NodeSet& Dst) { + + ValueState* St = GetState(Pred); + + for (const ScopedDecl* D = DS->getDecl(); D; D = D->getNextDeclarator()) + if (const VarDecl* VD = dyn_cast(D)) { + + // FIXME: Add support for local arrays. + if (VD->getType()->isArrayType()) + continue; + + const Expr* Ex = VD->getInit(); + + if (!VD->hasGlobalStorage() || VD->getStorageClass() == VarDecl::Static) { + + // In this context, Static => Local variable. + + assert (!VD->getStorageClass() == VarDecl::Static || + !isa(VD)); + + // If there is no initializer, set the value of the + // variable to "Undefined". + // + // FIXME: static variables may have an initializer, but the second + // time a function is called those values may not be current. + + QualType T = VD->getType(); + + if ( VD->getStorageClass() == VarDecl::Static) { + + // C99: 6.7.8 Initialization + // If an object that has static storage duration is not initialized + // explicitly, then: + // —if it has pointer type, it is initialized to a null pointer; + // —if it has arithmetic type, it is initialized to (positive or + // unsigned) zero; + + // FIXME: Handle structs. Now we treat their values as unknown. + + if (T->isPointerType()) { + + St = SetRVal(St, lval::DeclVal(VD), + lval::ConcreteInt(BasicVals.getValue(0, T))); + } + else if (T->isIntegerType()) { + + St = SetRVal(St, lval::DeclVal(VD), + nonlval::ConcreteInt(BasicVals.getValue(0, T))); + } + + + } + else { + + // FIXME: Handle structs. Now we treat them as unknown. What + // we need to do is treat their members as unknown. + + if (T->isPointerType() || T->isIntegerType()) + St = SetRVal(St, lval::DeclVal(VD), + Ex ? GetRVal(St, Ex) : UndefinedVal()); + } + } + } + + Nodify(Dst, DS, Pred, St); +} + + +void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, + NodeTy* Pred, NodeSet& Dst) { + + assert (Ex == CurrentStmt && getCFG().isBlkExpr(Ex)); + + ValueState* St = GetState(Pred); + RVal X = GetBlkExprRVal(St, Ex); + + assert (X.isUndef()); + + Expr* SE = (Expr*) cast(X).getData(); + + assert (SE); + + X = GetBlkExprRVal(St, SE); + + // Make sure that we invalidate the previous binding. + Nodify(Dst, Ex, Pred, StateMgr.SetRVal(St, Ex, X, true, true)); +} + +/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type). +void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, + NodeTy* Pred, + NodeSet& Dst) { + + QualType T = Ex->getArgumentType(); + uint64_t amt; + + if (Ex->isSizeOf()) { + + // FIXME: Add support for VLAs. + if (!T.getTypePtr()->isConstantSizeType()) + return; + + amt = 1; // Handle sizeof(void) + + if (T != getContext().VoidTy) + amt = getContext().getTypeSize(T) / 8; + + } + else // Get alignment of the type. + amt = getContext().getTypeAlign(T) / 8; + + Nodify(Dst, Ex, Pred, + SetRVal(GetState(Pred), Ex, + NonLVal::MakeVal(BasicVals, amt, Ex->getType()))); +} + +void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, + NodeSet& Dst, bool GetLVal) { + + Expr* Ex = U->getSubExpr()->IgnoreParens(); + + NodeSet DstTmp; + + if (isa(Ex)) + DstTmp.Add(Pred); + else + Visit(Ex, Pred, DstTmp); + + for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) { + + NodeTy* N = *I; + ValueState* St = GetState(N); + + // FIXME: Bifurcate when dereferencing a symbolic with no constraints? + + RVal V = GetRVal(St, Ex); + + // Check for dereferences of undefined values. + + if (V.isUndef()) { + + NodeTy* Succ = Builder->generateNode(U, St, N); + + if (Succ) { + Succ->markAsSink(); + UndefDeref.insert(Succ); + } + + continue; + } + + // Check for dereferences of unknown values. Treat as No-Ops. + + if (V.isUnknown()) { + Dst.Add(N); + continue; + } + + // After a dereference, one of two possible situations arise: + // (1) A crash, because the pointer was NULL. + // (2) The pointer is not NULL, and the dereference works. + // + // We add these assumptions. + + LVal LV = cast(V); + bool isFeasibleNotNull; + + // "Assume" that the pointer is Not-NULL. + + ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull); + + if (isFeasibleNotNull) { + + if (GetLVal) Nodify(Dst, U, N, SetRVal(StNotNull, U, LV)); + else { + + // FIXME: Currently symbolic analysis "generates" new symbols + // for the contents of values. We need a better approach. + + Nodify(Dst, U, N, SetRVal(StNotNull, U, + GetRVal(StNotNull, LV, U->getType()))); + } + } + + bool isFeasibleNull; + + // Now "assume" that the pointer is NULL. + + ValueState* StNull = Assume(St, LV, false, isFeasibleNull); + + if (isFeasibleNull) { + + // We don't use "Nodify" here because the node will be a sink + // and we have no intention of processing it later. + + NodeTy* NullNode = Builder->generateNode(U, StNull, N); + + if (NullNode) { + + NullNode->markAsSink(); + + if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode); + else ExplicitNullDeref.insert(NullNode); + } + } + } +} + +void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, + NodeSet& Dst) { + + NodeSet S1; + + assert (U->getOpcode() != UnaryOperator::Deref); + assert (U->getOpcode() != UnaryOperator::SizeOf); + assert (U->getOpcode() != UnaryOperator::AlignOf); + + bool use_GetLVal = false; + + switch (U->getOpcode()) { + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + case UnaryOperator::AddrOf: + // Evalue subexpression as an LVal. + use_GetLVal = true; + VisitLVal(U->getSubExpr(), Pred, S1); + break; + + default: + Visit(U->getSubExpr(), Pred, S1); + break; + } + + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { + + NodeTy* N1 = *I1; + ValueState* St = GetState(N1); + + RVal SubV = use_GetLVal ? GetLVal(St, U->getSubExpr()) : + GetRVal(St, U->getSubExpr()); + + if (SubV.isUnknown()) { + Dst.Add(N1); + continue; + } + + if (SubV.isUndef()) { + Nodify(Dst, U, N1, SetRVal(St, U, SubV)); + continue; + } + + if (U->isIncrementDecrementOp()) { + + // Handle ++ and -- (both pre- and post-increment). + + LVal SubLV = cast(SubV); + RVal V = GetRVal(St, SubLV, U->getType()); + + if (V.isUnknown()) { + Dst.Add(N1); + continue; + } + + // Propagate undefined values. + if (V.isUndef()) { + Nodify(Dst, U, N1, SetRVal(St, U, V)); + continue; + } + + // Handle all other values. + + BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add + : BinaryOperator::Sub; + + RVal Result = EvalBinOp(Op, V, MakeConstantVal(1U, U)); + + if (U->isPostfix()) + St = SetRVal(SetRVal(St, U, V), SubLV, Result); + else + St = SetRVal(SetRVal(St, U, Result), SubLV, Result); + + Nodify(Dst, U, N1, St); + continue; + } + + // Handle all other unary operators. + + switch (U->getOpcode()) { + + case UnaryOperator::Extension: + St = SetRVal(St, U, SubV); + break; + + case UnaryOperator::Minus: + St = SetRVal(St, U, EvalMinus(U, cast(SubV))); + break; + + case UnaryOperator::Not: + St = SetRVal(St, U, EvalComplement(cast(SubV))); + break; + + case UnaryOperator::LNot: + + // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." + // + // Note: technically we do "E == 0", but this is the same in the + // transfer functions as "0 == E". + + if (isa(SubV)) { + lval::ConcreteInt V(BasicVals.getZeroWithPtrWidth()); + RVal Result = EvalBinOp(BinaryOperator::EQ, cast(SubV), V); + St = SetRVal(St, U, Result); + } + else { + Expr* Ex = U->getSubExpr(); + nonlval::ConcreteInt V(BasicVals.getValue(0, Ex->getType())); + RVal Result = EvalBinOp(BinaryOperator::EQ, cast(SubV), V); + St = SetRVal(St, U, Result); + } + + break; + + case UnaryOperator::AddrOf: { + assert (isa(SubV)); + St = SetRVal(St, U, SubV); + break; + } + + default: ; + assert (false && "Not implemented."); + } + + Nodify(Dst, U, N1, St); + } +} + +void GRExprEngine::VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, + NodeSet& Dst) { + + QualType T = U->getSubExpr()->getType(); + + // FIXME: Add support for VLAs. + if (!T.getTypePtr()->isConstantSizeType()) + return; + + uint64_t size = getContext().getTypeSize(T) / 8; + ValueState* St = GetState(Pred); + St = SetRVal(St, U, NonLVal::MakeVal(BasicVals, size, U->getType())); + + Nodify(Dst, U, Pred, St); +} + +void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { + + if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) { + Dst.Add(Pred); + return; + } + + Ex = Ex->IgnoreParens(); + + if (isa(Ex)) { + Dst.Add(Pred); + return; + } + + if (UnaryOperator* U = dyn_cast(Ex)) + if (U->getOpcode() == UnaryOperator::Deref) { + VisitDeref(U, Pred, Dst, true); + return; + } + + Visit(Ex, Pred, Dst); +} + +void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, + GRExprEngine::NodeTy* Pred, + GRExprEngine::NodeSet& Dst) { + NodeSet S1; + + if (B->isAssignmentOp()) + VisitLVal(B->getLHS(), Pred, S1); + else + Visit(B->getLHS(), Pred, S1); + + for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { + + NodeTy* N1 = *I1; + + // When getting the value for the LHS, check if we are in an assignment. + // In such cases, we want to (initially) treat the LHS as an LVal, + // so we use GetLVal instead of GetRVal so that DeclRefExpr's are + // evaluated to LValDecl's instead of to an NonLVal. + + RVal LeftV = B->isAssignmentOp() ? GetLVal(GetState(N1), B->getLHS()) + : GetRVal(GetState(N1), B->getLHS()); + + // Visit the RHS... + + NodeSet S2; + Visit(B->getRHS(), N1, S2); + + // Process the binary operator. + + for (NodeSet::iterator I2 = S2.begin(), E2 = S2.end(); I2 != E2; ++I2) { + + NodeTy* N2 = *I2; + ValueState* St = GetState(N2); + Expr* RHS = B->getRHS(); + RVal RightV = GetRVal(St, RHS); + + BinaryOperator::Opcode Op = B->getOpcode(); + + if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem) + && RHS->getType()->isIntegerType()) { + + // Check if the denominator is undefined. + + if (!RightV.isUnknown()) { + + if (RightV.isUndef()) { + NodeTy* DivUndef = Builder->generateNode(B, St, N2); + + if (DivUndef) { + DivUndef->markAsSink(); + ExplicitBadDivides.insert(DivUndef); + } + + continue; + } + + // Check for divide/remainder-by-zero. + // + // First, "assume" that the denominator is 0 or undefined. + + bool isFeasibleZero = false; + ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero); + + // Second, "assume" that the denominator cannot be 0. + + bool isFeasibleNotZero = false; + St = Assume(St, RightV, true, isFeasibleNotZero); + + // Create the node for the divide-by-zero (if it occurred). + + if (isFeasibleZero) + if (NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2)) { + DivZeroNode->markAsSink(); + + if (isFeasibleNotZero) + ImplicitBadDivides.insert(DivZeroNode); + else + ExplicitBadDivides.insert(DivZeroNode); + + } + + if (!isFeasibleNotZero) + continue; + } + + // Fall-through. The logic below processes the divide. + } + + + if (Op <= BinaryOperator::Or) { + + // Process non-assignements except commas or short-circuited + // logical expressions (LAnd and LOr). + + RVal Result = EvalBinOp(Op, LeftV, RightV); + + if (Result.isUnknown()) { + Dst.Add(N2); + continue; + } + + if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) { + + // The operands were not undefined, but the result is undefined. + + if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) { + UndefNode->markAsSink(); + UndefResults.insert(UndefNode); + } + + continue; + } + + Nodify(Dst, B, N2, SetRVal(St, B, Result)); + continue; + } + + // Process assignments. + + switch (Op) { + + case BinaryOperator::Assign: { + + // Simple assignments. + + if (LeftV.isUndef()) { + HandleUndefinedStore(B, N2); + continue; + } + + // EXPERIMENTAL: "Conjured" symbols. + + if (RightV.isUnknown()) { + unsigned Count = Builder->getCurrentBlockCount(); + SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count); + + RightV = B->getRHS()->getType()->isPointerType() + ? cast(lval::SymbolVal(Sym)) + : cast(nonlval::SymbolVal(Sym)); + } + + // Even if the LHS evaluates to an unknown L-Value, the entire + // expression still evaluates to the RHS. + + if (LeftV.isUnknown()) { + St = SetRVal(St, B, RightV); + break; + } + + // Simulate the effects of a "store": bind the value of the RHS + // to the L-Value represented by the LHS. + + St = SetRVal(SetRVal(St, B, RightV), cast(LeftV), RightV); + break; + } + + // Compound assignment operators. + + default: { + + assert (B->isCompoundAssignmentOp()); + + if (Op >= BinaryOperator::AndAssign) + ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And); + else + ((int&) Op) -= BinaryOperator::MulAssign; + + // Check if the LHS is undefined. + + if (LeftV.isUndef()) { + HandleUndefinedStore(B, N2); + continue; + } + + if (LeftV.isUnknown()) { + assert (isa(GetRVal(St, B))); + Dst.Add(N2); + continue; + } + + // At this pointer we know that the LHS evaluates to an LVal + // that is neither "Unknown" or "Undefined." + + LVal LeftLV = cast(LeftV); + + // Fetch the value of the LHS (the value of the variable, etc.). + + RVal V = GetRVal(GetState(N1), LeftLV, B->getLHS()->getType()); + + // Propagate undefined value (left-side). We + // propogate undefined values for the RHS below when + // we also check for divide-by-zero. + + if (V.isUndef()) { + St = SetRVal(St, B, V); + break; + } + + // Propagate unknown values. + + if (V.isUnknown()) { + // The value bound to LeftV is unknown. Thus we just + // propagate the current node (as "B" is already bound to nothing). + assert (isa(GetRVal(St, B))); + Dst.Add(N2); + continue; + } + + if (RightV.isUnknown()) { + assert (isa(GetRVal(St, B))); + St = SetRVal(St, LeftLV, UnknownVal()); + break; + } + + // At this point: + // + // The LHS is not Undef/Unknown. + // The RHS is not Unknown. + + // Get the computation type. + QualType CTy = cast(B)->getComputationType(); + + // Perform promotions. + V = EvalCast(V, CTy); + RightV = EvalCast(RightV, CTy); + + // Evaluate operands and promote to result type. + + if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem) + && RHS->getType()->isIntegerType()) { + + // Check if the denominator is undefined. + + if (RightV.isUndef()) { + NodeTy* DivUndef = Builder->generateNode(B, St, N2); + + if (DivUndef) { + DivUndef->markAsSink(); + ExplicitBadDivides.insert(DivUndef); + } + + continue; + } + + // First, "assume" that the denominator is 0. + + bool isFeasibleZero = false; + ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero); + + // Second, "assume" that the denominator cannot be 0. + + bool isFeasibleNotZero = false; + St = Assume(St, RightV, true, isFeasibleNotZero); + + // Create the node for the divide-by-zero error (if it occurred). + + if (isFeasibleZero) { + NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2); + + if (DivZeroNode) { + DivZeroNode->markAsSink(); + + if (isFeasibleNotZero) + ImplicitBadDivides.insert(DivZeroNode); + else + ExplicitBadDivides.insert(DivZeroNode); + } + } + + if (!isFeasibleNotZero) + continue; + + // Fall-through. The logic below processes the divide. + } + else { + + // Propagate undefined values (right-side). + + if (RightV.isUndef()) { + St = SetRVal(SetRVal(St, B, RightV), LeftLV, RightV); + break; + } + + } + + RVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType()); + + if (Result.isUndef()) { + + // The operands were not undefined, but the result is undefined. + + if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) { + UndefNode->markAsSink(); + UndefResults.insert(UndefNode); + } + + continue; + } + + St = SetRVal(SetRVal(St, B, Result), LeftLV, Result); + } + } + + Nodify(Dst, B, N2, St); + } + } +} + +void GRExprEngine::HandleUndefinedStore(Stmt* S, NodeTy* Pred) { + NodeTy* N = Builder->generateNode(S, GetState(Pred), Pred); + N->markAsSink(); + UndefStores.insert(N); +} + +void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { + + // FIXME: add metadata to the CFG so that we can disable + // this check when we KNOW that there is no block-level subexpression. + // The motivation is that this check requires a hashtable lookup. + + if (S != CurrentStmt && getCFG().isBlkExpr(S)) { + Dst.Add(Pred); + return; + } + + switch (S->getStmtClass()) { + + default: + // Cases we intentionally have "default" handle: + // AddrLabelExpr, IntegerLiteral, CharacterLiteral + + Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. + break; + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast(S); + + if (B->isLogicalOp()) { + VisitLogicalExpr(B, Pred, Dst); + break; + } + else if (B->getOpcode() == BinaryOperator::Comma) { + ValueState* St = GetState(Pred); + Nodify(Dst, B, Pred, SetRVal(St, B, GetRVal(St, B->getRHS()))); + break; + } + + VisitBinaryOperator(cast(S), Pred, Dst); + break; + } + + case Stmt::CallExprClass: { + CallExpr* C = cast(S); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + break; + } + + case Stmt::CastExprClass: { + CastExpr* C = cast(S); + VisitCast(C, C->getSubExpr(), Pred, Dst); + break; + } + + // FIXME: ChooseExpr is really a constant. We need to fix + // the CFG do not model them as explicit control-flow. + + case Stmt::ChooseExprClass: { // __builtin_choose_expr + ChooseExpr* C = cast(S); + VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + break; + } + + case Stmt::CompoundAssignOperatorClass: + VisitBinaryOperator(cast(S), Pred, Dst); + break; + + case Stmt::ConditionalOperatorClass: { // '?' operator + ConditionalOperator* C = cast(S); + VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + break; + } + + case Stmt::DeclRefExprClass: + VisitDeclRefExpr(cast(S), Pred, Dst); + break; + + case Stmt::DeclStmtClass: + VisitDeclStmt(cast(S), Pred, Dst); + break; + + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr* C = cast(S); + VisitCast(C, C->getSubExpr(), Pred, Dst); + break; + } + + case Stmt::ParenExprClass: + Visit(cast(S)->getSubExpr(), Pred, Dst); + break; + + case Stmt::SizeOfAlignOfTypeExprClass: + VisitSizeOfAlignOfTypeExpr(cast(S), Pred, Dst); + break; + + case Stmt::StmtExprClass: { + StmtExpr* SE = cast(S); + + ValueState* St = GetState(Pred); + + // FIXME: Not certain if we can have empty StmtExprs. If so, we should + // probably just remove these from the CFG. + assert (!SE->getSubStmt()->body_empty()); + + if (Expr* LastExpr = dyn_cast(*SE->getSubStmt()->body_rbegin())) + Nodify(Dst, SE, Pred, SetRVal(St, SE, GetRVal(St, LastExpr))); + else + Dst.Add(Pred); + + break; + } + + // FIXME: We may wish to always bind state to ReturnStmts so + // that users can quickly query what was the state at the + // exit points of a function. + + case Stmt::ReturnStmtClass: { + if (Expr* R = cast(S)->getRetValue()) + Visit(R, Pred, Dst); + else + Dst.Add(Pred); + + break; + } + + case Stmt::UnaryOperatorClass: { + UnaryOperator* U = cast(S); + + switch (U->getOpcode()) { + case UnaryOperator::Deref: VisitDeref(U, Pred, Dst); break; + case UnaryOperator::Plus: Visit(U->getSubExpr(), Pred, Dst); break; + case UnaryOperator::SizeOf: VisitSizeOfExpr(U, Pred, Dst); break; + default: VisitUnaryOperator(U, Pred, Dst); break; + } + + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Assume" logic. +//===----------------------------------------------------------------------===// + +ValueState* GRExprEngine::Assume(ValueState* St, LVal Cond, + bool Assumption, + bool& isFeasible) { + switch (Cond.getSubKind()) { + default: + assert (false && "'Assume' not implemented for this LVal."); + return St; + + case lval::SymbolValKind: + if (Assumption) + return AssumeSymNE(St, cast(Cond).getSymbol(), + BasicVals.getZeroWithPtrWidth(), isFeasible); + else + return AssumeSymEQ(St, cast(Cond).getSymbol(), + BasicVals.getZeroWithPtrWidth(), isFeasible); + + + case lval::DeclValKind: + case lval::FuncValKind: + case lval::GotoLabelKind: + isFeasible = Assumption; + return St; + + case lval::ConcreteIntKind: { + bool b = cast(Cond).getValue() != 0; + isFeasible = b ? Assumption : !Assumption; + return St; + } + } +} + +ValueState* GRExprEngine::Assume(ValueState* St, NonLVal Cond, + bool Assumption, + bool& isFeasible) { + switch (Cond.getSubKind()) { + default: + assert (false && "'Assume' not implemented for this NonLVal."); + return St; + + + case nonlval::SymbolValKind: { + nonlval::SymbolVal& SV = cast(Cond); + SymbolID sym = SV.getSymbol(); + + if (Assumption) + return AssumeSymNE(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)), + isFeasible); + else + return AssumeSymEQ(St, sym, BasicVals.getValue(0, SymMgr.getType(sym)), + isFeasible); + } + + case nonlval::SymIntConstraintValKind: + return + AssumeSymInt(St, Assumption, + cast(Cond).getConstraint(), + isFeasible); + + case nonlval::ConcreteIntKind: { + bool b = cast(Cond).getValue() != 0; + isFeasible = b ? Assumption : !Assumption; + return St; + } + } +} + +ValueState* +GRExprEngine::AssumeSymNE(ValueState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + + // First, determine if sym == X, where X != V. + if (const llvm::APSInt* X = St->getSymVal(sym)) { + isFeasible = *X != V; + return St; + } + + // Second, determine if sym != V. + if (St->isNotEqual(sym, V)) { + isFeasible = true; + return St; + } + + // If we reach here, sym is not a constant and we don't know if it is != V. + // Make that assumption. + + isFeasible = true; + return StateMgr.AddNE(St, sym, V); +} + +ValueState* +GRExprEngine::AssumeSymEQ(ValueState* St, SymbolID sym, + const llvm::APSInt& V, bool& isFeasible) { + + // First, determine if sym == X, where X != V. + if (const llvm::APSInt* X = St->getSymVal(sym)) { + isFeasible = *X == V; + return St; + } + + // Second, determine if sym != V. + if (St->isNotEqual(sym, V)) { + isFeasible = false; + return St; + } + + // If we reach here, sym is not a constant and we don't know if it is == V. + // Make that assumption. + + isFeasible = true; + return StateMgr.AddEQ(St, sym, V); +} + +ValueState* +GRExprEngine::AssumeSymInt(ValueState* St, bool Assumption, + const SymIntConstraint& C, bool& isFeasible) { + + switch (C.getOpcode()) { + default: + // No logic yet for other operators. + isFeasible = true; + return St; + + case BinaryOperator::EQ: + if (Assumption) + return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible); + else + return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible); + + case BinaryOperator::NE: + if (Assumption) + return AssumeSymNE(St, C.getSymbol(), C.getInt(), isFeasible); + else + return AssumeSymEQ(St, C.getSymbol(), C.getInt(), isFeasible); + } +} + +//===----------------------------------------------------------------------===// +// Visualization. +//===----------------------------------------------------------------------===// + +#ifndef NDEBUG +static GRExprEngine* GraphPrintCheckerState; +static SourceManager* GraphPrintSourceManager; +static ValueState::CheckerStatePrinter* GraphCheckerStatePrinter; + +namespace llvm { +template<> +struct VISIBILITY_HIDDEN DOTGraphTraits : + public DefaultDOTGraphTraits { + + static void PrintVarBindings(std::ostream& Out, ValueState* St) { + + Out << "Variables:\\l"; + + bool isFirst = true; + + for (ValueState::vb_iterator I=St->vb_begin(), E=St->vb_end(); I!=E;++I) { + + if (isFirst) + isFirst = false; + else + Out << "\\l"; + + Out << ' ' << I.getKey()->getName() << " : "; + I.getData().print(Out); + } + + } + + + static void PrintSubExprBindings(std::ostream& Out, ValueState* St){ + + bool isFirst = true; + + for (ValueState::seb_iterator I=St->seb_begin(), E=St->seb_end();I!=E;++I) { + + if (isFirst) { + Out << "\\l\\lSub-Expressions:\\l"; + isFirst = false; + } + else + Out << "\\l"; + + Out << " (" << (void*) I.getKey() << ") "; + I.getKey()->printPretty(Out); + Out << " : "; + I.getData().print(Out); + } + } + + static void PrintBlkExprBindings(std::ostream& Out, ValueState* St){ + + bool isFirst = true; + + for (ValueState::beb_iterator I=St->beb_begin(), E=St->beb_end(); I!=E;++I){ + if (isFirst) { + Out << "\\l\\lBlock-level Expressions:\\l"; + isFirst = false; + } + else + Out << "\\l"; + + Out << " (" << (void*) I.getKey() << ") "; + I.getKey()->printPretty(Out); + Out << " : "; + I.getData().print(Out); + } + } + + static void PrintEQ(std::ostream& Out, ValueState* St) { + ValueState::ConstEqTy CE = St->ConstEq; + + if (CE.isEmpty()) + return; + + Out << "\\l\\|'==' constraints:"; + + for (ValueState::ConstEqTy::iterator I=CE.begin(), E=CE.end(); I!=E;++I) + Out << "\\l $" << I.getKey() << " : " << I.getData()->toString(); + } + + static void PrintNE(std::ostream& Out, ValueState* St) { + ValueState::ConstNotEqTy NE = St->ConstNotEq; + + if (NE.isEmpty()) + return; + + Out << "\\l\\|'!=' constraints:"; + + for (ValueState::ConstNotEqTy::iterator I=NE.begin(), EI=NE.end(); + I != EI; ++I){ + + Out << "\\l $" << I.getKey() << " : "; + bool isFirst = true; + + ValueState::IntSetTy::iterator J=I.getData().begin(), + EJ=I.getData().end(); + for ( ; J != EJ; ++J) { + if (isFirst) isFirst = false; + else Out << ", "; + + Out << (*J)->toString(); + } + } + } + + static std::string getNodeAttributes(const GRExprEngine::NodeTy* N, void*) { + + if (GraphPrintCheckerState->isImplicitNullDeref(N) || + GraphPrintCheckerState->isExplicitNullDeref(N) || + GraphPrintCheckerState->isUndefDeref(N) || + GraphPrintCheckerState->isUndefStore(N) || + GraphPrintCheckerState->isUndefControlFlow(N) || + GraphPrintCheckerState->isExplicitBadDivide(N) || + GraphPrintCheckerState->isImplicitBadDivide(N) || + GraphPrintCheckerState->isUndefResult(N) || + GraphPrintCheckerState->isBadCall(N) || + GraphPrintCheckerState->isUndefArg(N)) + return "color=\"red\",style=\"filled\""; + + if (GraphPrintCheckerState->isNoReturnCall(N)) + return "color=\"blue\",style=\"filled\""; + + return ""; + } + + static std::string getNodeLabel(const GRExprEngine::NodeTy* N, void*) { + std::ostringstream Out; + + // Program Location. + ProgramPoint Loc = N->getLocation(); + + switch (Loc.getKind()) { + case ProgramPoint::BlockEntranceKind: + Out << "Block Entrance: B" + << cast(Loc).getBlock()->getBlockID(); + break; + + case ProgramPoint::BlockExitKind: + assert (false); + break; + + case ProgramPoint::PostStmtKind: { + const PostStmt& L = cast(Loc); + Stmt* S = L.getStmt(); + SourceLocation SLoc = S->getLocStart(); + + Out << S->getStmtClassName() << ' ' << (void*) S << ' '; + S->printPretty(Out); + + if (SLoc.isFileID()) { + Out << "\\lline=" + << GraphPrintSourceManager->getLineNumber(SLoc) << " col=" + << GraphPrintSourceManager->getColumnNumber(SLoc) << "\\l"; + } + + if (GraphPrintCheckerState->isImplicitNullDeref(N)) + Out << "\\|Implicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isExplicitNullDeref(N)) + Out << "\\|Explicit-Null Dereference.\\l"; + else if (GraphPrintCheckerState->isUndefDeref(N)) + Out << "\\|Dereference of undefialied value.\\l"; + else if (GraphPrintCheckerState->isUndefStore(N)) + Out << "\\|Store to Undefined LVal."; + else if (GraphPrintCheckerState->isExplicitBadDivide(N)) + Out << "\\|Explicit divide-by zero or undefined value."; + else if (GraphPrintCheckerState->isImplicitBadDivide(N)) + Out << "\\|Implicit divide-by zero or undefined value."; + else if (GraphPrintCheckerState->isUndefResult(N)) + Out << "\\|Result of operation is undefined."; + else if (GraphPrintCheckerState->isNoReturnCall(N)) + Out << "\\|Call to function marked \"noreturn\"."; + else if (GraphPrintCheckerState->isBadCall(N)) + Out << "\\|Call to NULL/Undefined."; + else if (GraphPrintCheckerState->isUndefArg(N)) + Out << "\\|Argument in call is undefined"; + + break; + } + + default: { + const BlockEdge& E = cast(Loc); + Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" + << E.getDst()->getBlockID() << ')'; + + if (Stmt* T = E.getSrc()->getTerminator()) { + + SourceLocation SLoc = T->getLocStart(); + + Out << "\\|Terminator: "; + + E.getSrc()->printTerminator(Out); + + if (SLoc.isFileID()) { + Out << "\\lline=" + << GraphPrintSourceManager->getLineNumber(SLoc) << " col=" + << GraphPrintSourceManager->getColumnNumber(SLoc); + } + + if (isa(T)) { + Stmt* Label = E.getDst()->getLabel(); + + if (Label) { + if (CaseStmt* C = dyn_cast(Label)) { + Out << "\\lcase "; + C->getLHS()->printPretty(Out); + + if (Stmt* RHS = C->getRHS()) { + Out << " .. "; + RHS->printPretty(Out); + } + + Out << ":"; + } + else { + assert (isa(Label)); + Out << "\\ldefault:"; + } + } + else + Out << "\\l(implicit) default:"; + } + else if (isa(T)) { + // FIXME + } + else { + Out << "\\lCondition: "; + if (*E.getSrc()->succ_begin() == E.getDst()) + Out << "true"; + else + Out << "false"; + } + + Out << "\\l"; + } + + if (GraphPrintCheckerState->isUndefControlFlow(N)) { + Out << "\\|Control-flow based on\\lUndefined value.\\l"; + } + } + } + + Out << "\\|StateID: " << (void*) N->getState() << "\\|"; + + N->getState()->printDOT(Out, GraphCheckerStatePrinter); + + Out << "\\l"; + return Out.str(); + } +}; +} // end llvm namespace +#endif + +#ifndef NDEBUG + +template +GRExprEngine::NodeTy* GetGraphNode(ITERATOR I) { return *I; } + +template <> +GRExprEngine::NodeTy* +GetGraphNode::iterator> + (llvm::DenseMap::iterator I) { + return I->first; +} + +template +static void AddSources(llvm::SmallVector& Sources, + ITERATOR I, ITERATOR E) { + + llvm::SmallPtrSet CachedSources; + + for ( ; I != E; ++I ) { + GRExprEngine::NodeTy* N = GetGraphNode(I); + void* p = N->getLocation().getRawData(); + + if (CachedSources.count(p)) + continue; + + CachedSources.insert(p); + + Sources.push_back(N); + } +} +#endif + +void GRExprEngine::ViewGraph(bool trim) { +#ifndef NDEBUG + if (trim) { + llvm::SmallVector Src; + AddSources(Src, null_derefs_begin(), null_derefs_end()); + AddSources(Src, undef_derefs_begin(), undef_derefs_end()); + AddSources(Src, explicit_bad_divides_begin(), explicit_bad_divides_end()); + AddSources(Src, undef_results_begin(), undef_results_end()); + AddSources(Src, bad_calls_begin(), bad_calls_end()); + AddSources(Src, undef_arg_begin(), undef_arg_end()); + AddSources(Src, undef_branches_begin(), undef_branches_end()); + + ViewGraph(&Src[0], &Src[0]+Src.size()); + } + else { + GraphPrintCheckerState = this; + GraphPrintSourceManager = &getContext().getSourceManager(); + GraphCheckerStatePrinter = TF->getCheckerStatePrinter(); + + llvm::ViewGraph(*G.roots_begin(), "GRExprEngine"); + + GraphPrintCheckerState = NULL; + GraphPrintSourceManager = NULL; + GraphCheckerStatePrinter = NULL; + } +#endif +} + +void GRExprEngine::ViewGraph(NodeTy** Beg, NodeTy** End) { +#ifndef NDEBUG + GraphPrintCheckerState = this; + GraphPrintSourceManager = &getContext().getSourceManager(); + GraphCheckerStatePrinter = TF->getCheckerStatePrinter(); + + GRExprEngine::GraphTy* TrimmedG = G.Trim(Beg, End); + + if (!TrimmedG) + llvm::cerr << "warning: Trimmed ExplodedGraph is empty.\n"; + else { + llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedGRExprEngine"); + delete TrimmedG; + } + + GraphPrintCheckerState = NULL; + GraphPrintSourceManager = NULL; + GraphCheckerStatePrinter = NULL; +#endif +} diff --git a/clang/lib/Analysis/GRSimpleVals.cpp b/clang/lib/Analysis/GRSimpleVals.cpp new file mode 100644 index 00000000000..3777d53bf0b --- /dev/null +++ b/clang/lib/Analysis/GRSimpleVals.cpp @@ -0,0 +1,462 @@ +// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- 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 GRSimpleVals, a sub-class of GRTransferFuncs that +// provides transfer functions for performing simple value tracking with +// limited support for symbolics. +// +//===----------------------------------------------------------------------===// + +#include "GRSimpleVals.h" +#include "clang/Analysis/PathSensitive/ValueState.h" +#include "clang/Basic/Diagnostic.h" +#include + +using namespace clang; + +namespace clang { + +template +static inline ProgramPoint GetLocation(ITERATOR I) { + return (*I)->getLocation(); +} + +template <> +inline ProgramPoint GetLocation(GRExprEngine::undef_arg_iterator I) { + return I->first->getLocation(); +} + +static inline Stmt* GetStmt(const ProgramPoint& P) { + if (const PostStmt* PS = dyn_cast(&P)) { + return PS->getStmt(); + } + else if (const BlockEdge* BE = dyn_cast(&P)) { + return BE->getSrc()->getTerminator(); + } + + assert (false && "Unsupported ProgramPoint."); + return NULL; +} + +template +static void EmitDiag(Diagnostic& Diag, SourceManager& SrcMgr, + unsigned ErrorDiag, ITERATOR I) { + + Stmt* S = GetStmt(GetLocation(I)); + Diag.Report(FullSourceLoc(S->getLocStart(), SrcMgr), ErrorDiag); +} + + +template <> +static void EmitDiag(Diagnostic& Diag, SourceManager& SrcMgr, + unsigned ErrorDiag, GRExprEngine::undef_arg_iterator I) { + + Stmt* S1 = GetStmt(GetLocation(I)); + Expr* E2 = cast(I->second); + + SourceLocation Loc = S1->getLocStart(); + SourceRange R = E2->getSourceRange(); + Diag.Report(FullSourceLoc(Loc, SrcMgr), ErrorDiag, 0, 0, &R, 1); +} + +template +void EmitWarning(Diagnostic& Diag, SourceManager& SrcMgr, + ITERATOR I, ITERATOR E, const char* msg) { + + std::ostringstream Out; + Out << "[CHECKER] " << msg; + msg = Out.str().c_str(); + + bool isFirst = true; + unsigned ErrorDiag = 0; + llvm::SmallPtrSet CachedErrors; + + for (; I != E; ++I) { + + if (isFirst) { + isFirst = false; + ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, msg); + } + else { + + // HACK: Cache the location of the error. Don't emit the same + // warning for the same error type that occurs at the same program + // location but along a different path. + void* p = GetLocation(I).getRawData(); + + if (CachedErrors.count(p)) + continue; + + CachedErrors.insert(p); + } + + EmitDiag(Diag, SrcMgr, ErrorDiag, I); + } +} + +unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx, + Diagnostic& Diag, bool Visualize, bool TrimGraph) { + + if (Diag.hasErrorOccurred()) + return 0; + + GRCoreEngine Eng(cfg, CD, Ctx); + GRExprEngine* CheckerState = &Eng.getCheckerState(); + GRSimpleVals GRSV; + CheckerState->setTransferFunctions(GRSV); + + // Execute the worklist algorithm. + Eng.ExecuteWorkList(100000); + + SourceManager& SrcMgr = Ctx.getSourceManager(); + + EmitWarning(Diag, SrcMgr, + CheckerState->null_derefs_begin(), + CheckerState->null_derefs_end(), + "NULL pointer is dereferenced after it is checked for NULL."); + + EmitWarning(Diag, SrcMgr, + CheckerState->undef_derefs_begin(), + CheckerState->undef_derefs_end(), + "Dereference of undefined value."); + + EmitWarning(Diag, SrcMgr, + CheckerState->undef_derefs_begin(), + CheckerState->undef_derefs_end(), + "Dereference of undefined value."); + + EmitWarning(Diag, SrcMgr, + CheckerState->explicit_bad_divides_begin(), + CheckerState->explicit_bad_divides_end(), + "Division by zero/undefined value."); + + EmitWarning(Diag, SrcMgr, + CheckerState->undef_results_begin(), + CheckerState->undef_results_end(), + "Result of operation is undefined."); + + EmitWarning(Diag, SrcMgr, + CheckerState->bad_calls_begin(), + CheckerState->bad_calls_end(), + "Call using a NULL or undefined function pointer value."); + + EmitWarning(Diag, SrcMgr, + CheckerState->undef_arg_begin(), + CheckerState->undef_arg_end(), + "Pass-by-value argument in function or message expression is undefined."); + + EmitWarning(Diag, SrcMgr, + CheckerState->undef_branches_begin(), + CheckerState->undef_branches_end(), + "Branch condition evaluates to an uninitialized value."); + +#ifndef NDEBUG + if (Visualize) CheckerState->ViewGraph(TrimGraph); +#endif + + return Eng.getGraph().size(); +} + +} // end clang namespace + +//===----------------------------------------------------------------------===// +// Transfer function for Casts. +//===----------------------------------------------------------------------===// + +RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLVal X, QualType T) { + + if (!isa(X)) + return UnknownVal(); + + BasicValueFactory& BasicVals = Eng.getBasicVals(); + + llvm::APSInt V = cast(X).getValue(); + V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType() + || T->isObjCQualifiedIdType()); + V.extOrTrunc(Eng.getContext().getTypeSize(T)); + + if (T->isPointerType()) + return lval::ConcreteInt(BasicVals.getValue(V)); + else + return nonlval::ConcreteInt(BasicVals.getValue(V)); +} + +// Casts. + +RVal GRSimpleVals::EvalCast(GRExprEngine& Eng, LVal X, QualType T) { + + if (T->isPointerType() || T->isReferenceType() || T->isObjCQualifiedIdType()) + return X; + + assert (T->isIntegerType()); + + if (!isa(X)) + return UnknownVal(); + + BasicValueFactory& BasicVals = Eng.getBasicVals(); + + llvm::APSInt V = cast(X).getValue(); + V.setIsUnsigned(T->isUnsignedIntegerType() || T->isPointerType()); + V.extOrTrunc(Eng.getContext().getTypeSize(T)); + + return nonlval::ConcreteInt(BasicVals.getValue(V)); +} + +// Unary operators. + +RVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLVal X){ + + switch (X.getSubKind()) { + + case nonlval::ConcreteIntKind: + return cast(X).EvalMinus(Eng.getBasicVals(), U); + + default: + return UnknownVal(); + } +} + +RVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLVal X) { + + switch (X.getSubKind()) { + + case nonlval::ConcreteIntKind: + return cast(X).EvalComplement(Eng.getBasicVals()); + + default: + return UnknownVal(); + } +} + +// Binary operators. + +RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, + NonLVal L, NonLVal R) { + + BasicValueFactory& BasicVals = Eng.getBasicVals(); + + while (1) { + + switch (L.getSubKind()) { + default: + return UnknownVal(); + + case nonlval::ConcreteIntKind: + + if (isa(R)) { + const nonlval::ConcreteInt& L_CI = cast(L); + const nonlval::ConcreteInt& R_CI = cast(R); + return L_CI.EvalBinOp(BasicVals, Op, R_CI); + } + else { + NonLVal tmp = R; + R = L; + L = tmp; + continue; + } + + case nonlval::SymbolValKind: { + + if (isa(R)) { + const SymIntConstraint& C = + BasicVals.getConstraint(cast(L).getSymbol(), Op, + cast(R).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + else + return UnknownVal(); + } + } + } +} + + +// Binary Operators (except assignments and comma). + +RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, + LVal L, LVal R) { + + switch (Op) { + + default: + return UnknownVal(); + + case BinaryOperator::EQ: + return EvalEQ(Eng, L, R); + + case BinaryOperator::NE: + return EvalNE(Eng, L, R); + } +} + +// Pointer arithmetic. + +RVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op, + LVal L, NonLVal R) { + return UnknownVal(); +} + +// Equality operators for LVals. + +RVal GRSimpleVals::EvalEQ(GRExprEngine& Eng, LVal L, LVal R) { + + BasicValueFactory& BasicVals = Eng.getBasicVals(); + + switch (L.getSubKind()) { + + default: + assert(false && "EQ not implemented for this LVal."); + return UnknownVal(); + + case lval::ConcreteIntKind: + + if (isa(R)) { + bool b = cast(L).getValue() == + cast(R).getValue(); + + return NonLVal::MakeIntTruthVal(BasicVals, b); + } + else if (isa(R)) { + + const SymIntConstraint& C = + BasicVals.getConstraint(cast(R).getSymbol(), + BinaryOperator::EQ, + cast(L).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + break; + + case lval::SymbolValKind: { + + if (isa(R)) { + const SymIntConstraint& C = + BasicVals.getConstraint(cast(L).getSymbol(), + BinaryOperator::EQ, + cast(R).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + // FIXME: Implement == for lval Symbols. This is mainly useful + // in iterator loops when traversing a buffer, e.g. while(z != zTerm). + // Since this is not useful for many checkers we'll punt on this for + // now. + + return UnknownVal(); + } + + case lval::DeclValKind: + case lval::FuncValKind: + case lval::GotoLabelKind: + return NonLVal::MakeIntTruthVal(BasicVals, L == R); + } + + return NonLVal::MakeIntTruthVal(BasicVals, false); +} + +RVal GRSimpleVals::EvalNE(GRExprEngine& Eng, LVal L, LVal R) { + + BasicValueFactory& BasicVals = Eng.getBasicVals(); + + switch (L.getSubKind()) { + + default: + assert(false && "NE not implemented for this LVal."); + return UnknownVal(); + + case lval::ConcreteIntKind: + + if (isa(R)) { + bool b = cast(L).getValue() != + cast(R).getValue(); + + return NonLVal::MakeIntTruthVal(BasicVals, b); + } + else if (isa(R)) { + const SymIntConstraint& C = + BasicVals.getConstraint(cast(R).getSymbol(), + BinaryOperator::NE, + cast(L).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + break; + + case lval::SymbolValKind: { + if (isa(R)) { + const SymIntConstraint& C = + BasicVals.getConstraint(cast(L).getSymbol(), + BinaryOperator::NE, + cast(R).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + // FIXME: Implement != for lval Symbols. This is mainly useful + // in iterator loops when traversing a buffer, e.g. while(z != zTerm). + // Since this is not useful for many checkers we'll punt on this for + // now. + + return UnknownVal(); + + break; + } + + case lval::DeclValKind: + case lval::FuncValKind: + case lval::GotoLabelKind: + return NonLVal::MakeIntTruthVal(BasicVals, L != R); + } + + return NonLVal::MakeIntTruthVal(BasicVals, true); +} + +//===----------------------------------------------------------------------===// +// Transfer function for Function Calls. +//===----------------------------------------------------------------------===// + +void GRSimpleVals::EvalCall(ExplodedNodeSet& Dst, + GRExprEngine& Eng, + GRStmtNodeBuilder& Builder, + CallExpr* CE, LVal L, + ExplodedNode* Pred) { + + ValueStateManager& StateMgr = Eng.getStateManager(); + ValueState* St = Builder.GetState(Pred); + + // Invalidate all arguments passed in by reference (LVals). + + for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + + RVal V = StateMgr.GetRVal(St, *I); + + if (isa(V)) + St = StateMgr.SetRVal(St, cast(V), UnknownVal()); + } + + // Make up a symbol for the return value of this function. + + if (CE->getType() != Eng.getContext().VoidTy) { + unsigned Count = Builder.getCurrentBlockCount(); + SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count); + + RVal X = CE->getType()->isPointerType() + ? cast(lval::SymbolVal(Sym)) + : cast(nonlval::SymbolVal(Sym)); + + St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false); + } + + Builder.Nodify(Dst, CE, Pred, St); +} diff --git a/clang/lib/Analysis/GRSimpleVals.h b/clang/lib/Analysis/GRSimpleVals.h new file mode 100644 index 00000000000..2b3d0fd00a2 --- /dev/null +++ b/clang/lib/Analysis/GRSimpleVals.h @@ -0,0 +1,71 @@ +// GRSimpleVals.h - Transfer functions for tracking simple values -*- 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 GRSimpleVals, a sub-class of GRTransferFuncs that +// provides transfer functions for performing simple value tracking with +// limited support for symbolics. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_GRSIMPLEVALS +#define LLVM_CLANG_ANALYSIS_GRSIMPLEVALS + +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" + +namespace clang { + +class GRSimpleVals : public GRTransferFuncs { +public: + GRSimpleVals() {} + virtual ~GRSimpleVals() {} + + // Casts. + + virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT); + virtual RVal EvalCast(GRExprEngine& Engine, LVal V, QualType CastT); + + // Unary Operators. + + virtual RVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLVal X); + + virtual RVal EvalComplement(GRExprEngine& Engine, NonLVal X); + + // Binary Operators. + + virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, + NonLVal L, NonLVal R); + + virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, + LVal L, LVal R); + + // Pointer arithmetic. + + virtual RVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, + LVal L, NonLVal R); + + // Calls. + + virtual void EvalCall(ExplodedNodeSet& Dst, + GRExprEngine& Engine, + GRStmtNodeBuilder& Builder, + CallExpr* CE, LVal L, + ExplodedNode* Pred); + +protected: + + // Equality operators for LVals. + + RVal EvalEQ(GRExprEngine& Engine, LVal L, LVal R); + RVal EvalNE(GRExprEngine& Engine, LVal L, LVal R); +}; + +} // end clang namespace + +#endif diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp new file mode 100644 index 00000000000..e59a4885911 --- /dev/null +++ b/clang/lib/Analysis/LiveVariables.cpp @@ -0,0 +1,246 @@ +//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Basic/SourceManager.h" +#include "clang/AST/Expr.h" +#include "clang/AST/CFG.h" +#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" +#include "clang/Analysis/FlowSensitive/DataflowSolver.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Compiler.h" + +#include +#include + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Dataflow initialization logic. +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN RegisterDecls + : public CFGRecStmtDeclVisitor { + + LiveVariables::AnalysisDataTy& AD; +public: + RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} + void VisitVarDecl(VarDecl* VD) { AD.Register(VD); } + CFG& getCFG() { return AD.getCFG(); } +}; +} // end anonymous namespace + + +LiveVariables::LiveVariables(CFG& cfg) { + // Register all referenced VarDecls. + getAnalysisData().setCFG(&cfg); + RegisterDecls R(getAnalysisData()); + cfg.VisitBlockStmts(R); +} + +//===----------------------------------------------------------------------===// +// Transfer functions. +//===----------------------------------------------------------------------===// + +namespace { + +static const bool Alive = true; +static const bool Dead = false; + +class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor{ + LiveVariables::AnalysisDataTy& AD; + LiveVariables::ValTy LiveState; +public: + TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} + + LiveVariables::ValTy& getVal() { return LiveState; } + CFG& getCFG() { return AD.getCFG(); } + + void VisitDeclRefExpr(DeclRefExpr* DR); + void VisitBinaryOperator(BinaryOperator* B); + void VisitAssign(BinaryOperator* B); + void VisitDeclStmt(DeclStmt* DS); + void VisitUnaryOperator(UnaryOperator* U); + void Visit(Stmt *S); +}; + +void TransferFuncs::Visit(Stmt *S) { + if (AD.Observer) + AD.Observer->ObserveStmt(S,AD,LiveState); + + if (S == getCurrentBlkStmt()) { + if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead; + StmtVisitor::Visit(S); + } + else if (!getCFG().isBlkExpr(S)) + StmtVisitor::Visit(S); + else + // For block-level expressions, mark that they are live. + LiveState(S,AD) = Alive; +} + +void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { + if (VarDecl* V = dyn_cast(DR->getDecl())) + LiveState(V,AD) = Alive; +} + +void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { + if (B->isAssignmentOp()) VisitAssign(B); + else VisitStmt(B); +} + +void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { + Expr *E = U->getSubExpr(); + + switch (U->getOpcode()) { + case UnaryOperator::SizeOf: return; + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + case UnaryOperator::AddrOf: + // Walk through the subexpressions, blasting through ParenExprs + // until we either find a DeclRefExpr or some non-DeclRefExpr + // expression. + if (DeclRefExpr* DR = dyn_cast(E->IgnoreParens())) + if (VarDecl* VD = dyn_cast(DR->getDecl())) { + // Treat the --/++/& operator as a kill. + LiveState(VD, AD) = Dead; + if (AD.Observer) { AD.Observer->ObserverKill(DR); } + return VisitDeclRefExpr(DR); + } + + // Fall-through. + + default: + return Visit(E); + } +} + +void TransferFuncs::VisitAssign(BinaryOperator* B) { + Expr* LHS = B->getLHS(); + + // Assigning to a variable? + if (DeclRefExpr* DR = dyn_cast(LHS->IgnoreParens())) { + LiveState(DR->getDecl(),AD) = Dead; + if (AD.Observer) { AD.Observer->ObserverKill(DR); } + + // Handle things like +=, etc., which also generate "uses" + // of a variable. Do this just by visiting the subexpression. + if (B->getOpcode() != BinaryOperator::Assign) + VisitDeclRefExpr(DR); + } + else // Not assigning to a variable. Process LHS as usual. + Visit(LHS); + + Visit(B->getRHS()); +} + +void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { + // Declarations effectively "kill" a variable since they cannot + // possibly be live before they are declared. + for (ScopedDecl* D = DS->getDecl(); D != NULL; D = D->getNextDeclarator()) + if (VarDecl* VD = dyn_cast(D)) { + LiveState(D,AD) = Dead; + + if (Expr* Init = VD->getInit()) + Visit(Init); + } +} + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Merge operator: if something is live on any successor block, it is live +// in the current block (a set union). +//===----------------------------------------------------------------------===// + +namespace { +typedef ExprDeclBitVector_Types::Union Merge; +typedef DataflowSolver Solver; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// External interface to run Liveness analysis. +//===----------------------------------------------------------------------===// + +void LiveVariables::runOnCFG(CFG& cfg) { + Solver S(*this); + S.runOnCFG(cfg); +} + +void LiveVariables::runOnAllBlocks(const CFG& cfg, + LiveVariables::ObserverTy* Obs, + bool recordStmtValues) { + Solver S(*this); + ObserverTy* OldObserver = getAnalysisData().Observer; + getAnalysisData().Observer = Obs; + S.runOnAllBlocks(cfg, recordStmtValues); + getAnalysisData().Observer = OldObserver; +} + +//===----------------------------------------------------------------------===// +// liveness queries +// + +bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const { + DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D); + return i.isValid() ? getBlockData(B).getBit(i) : false; +} + +bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const { + DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D); + return i.isValid() ? Live.getBit(i) : false; +} + +bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const { + return getStmtData(Loc)(StmtVal,getAnalysisData()); +} + +bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const { + return getStmtData(Loc)(D,getAnalysisData()); +} + +//===----------------------------------------------------------------------===// +// printing liveness state for debugging +// + +void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { + const AnalysisDataTy& AD = getAnalysisData(); + + for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), + E = AD.end_decl(); I!=E; ++I) + if (V.getDeclBit(I->second)) { + SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation()); + + fprintf(stderr, " %s <%s:%u:%u>\n", + I->first->getIdentifier()->getName(), + SM.getSourceName(PhysLoc), + SM.getLineNumber(PhysLoc), + SM.getColumnNumber(PhysLoc)); + } +} + +void LiveVariables::dumpBlockLiveness(SourceManager& M) const { + for (BlockDataMapTy::iterator I = getBlockDataMap().begin(), + E = getBlockDataMap().end(); I!=E; ++I) { + fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n", + I->first->getBlockID()); + + dumpLiveness(I->second,M); + } + + fprintf(stderr,"\n"); +} diff --git a/clang/lib/Analysis/Makefile b/clang/lib/Analysis/Makefile new file mode 100644 index 00000000000..b1d91781823 --- /dev/null +++ b/clang/lib/Analysis/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/Analysis/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements analyses built on top of source-level CFGs. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangAnalysis +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Analysis/ProgramPoint.cpp b/clang/lib/Analysis/ProgramPoint.cpp new file mode 100644 index 00000000000..c089e486988 --- /dev/null +++ b/clang/lib/Analysis/ProgramPoint.cpp @@ -0,0 +1,65 @@ +//= ProgramPoint.cpp - Program Points for Path-Sensitive Analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements methods for subclasses of ProgramPoint. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/CFG.h" +#include "clang/Analysis/ProgramPoint.h" + +using namespace clang; + +BlockEdge::BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2) { + if (B1->succ_size() == 1) { + assert (*(B1->succ_begin()) == B2); + Data = reinterpret_cast(B1) | BlockEdgeSrcKind; + } + else if (B2->pred_size() == 1) { + assert (*(B2->pred_begin()) == B1); + Data = reinterpret_cast(B2) | BlockEdgeDstKind; + } + else + Data = reinterpret_cast(cfg.getBlockEdgeImpl(B1,B2)) + | BlockEdgeAuxKind; +} + +CFGBlock* BlockEdge::getSrc() const { + switch (getKind()) { + default: + assert (false && "Invalid BlockEdgeKind."); + return NULL; + + case BlockEdgeSrcKind: + return reinterpret_cast(getRawPtr()); + + case BlockEdgeDstKind: + return *(reinterpret_cast(getRawPtr())->pred_begin()); + + case BlockEdgeAuxKind: + return reinterpret_cast(getRawPtr())->first; + } +} + +CFGBlock* BlockEdge::getDst() const { + switch (getKind()) { + default: + assert (false && "Invalid BlockEdgeKind."); + return NULL; + + case BlockEdgeSrcKind: + return *(reinterpret_cast(getRawPtr())->succ_begin()); + + case BlockEdgeDstKind: + return reinterpret_cast(getRawPtr()); + + case BlockEdgeAuxKind: + return reinterpret_cast(getRawPtr())->second; + } +} diff --git a/clang/lib/Analysis/RValues.cpp b/clang/lib/Analysis/RValues.cpp new file mode 100644 index 00000000000..a4b464949aa --- /dev/null +++ b/clang/lib/Analysis/RValues.cpp @@ -0,0 +1,389 @@ +//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- 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 RVal, LVal, and NonLVal, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/RValues.h" +#include "llvm/Support/Streams.h" + +using namespace clang; +using llvm::dyn_cast; +using llvm::cast; +using llvm::APSInt; + +//===----------------------------------------------------------------------===// +// Symbol Iteration. +//===----------------------------------------------------------------------===// + +RVal::symbol_iterator RVal::symbol_begin() const { + if (isa(this)) + return (symbol_iterator) (&Data); + else if (isa(this)) + return (symbol_iterator) (&Data); + else if (isa(this)) { + const SymIntConstraint& C = + cast(this)->getConstraint(); + + return (symbol_iterator) &C.getSymbol(); + } + + return NULL; +} + +RVal::symbol_iterator RVal::symbol_end() const { + symbol_iterator X = symbol_begin(); + return X ? X+1 : NULL; +} + +//===----------------------------------------------------------------------===// +// Transfer function dispatch for Non-LVals. +//===----------------------------------------------------------------------===// + +RVal +nonlval::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const nonlval::ConcreteInt& R) const { + + const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); + + if (X) + return nonlval::ConcreteInt(*X); + else + return UndefinedVal(); +} + + + // Bitwise-Complement. + +nonlval::ConcreteInt +nonlval::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const { + return BasicVals.getValue(~getValue()); +} + + // Unary Minus. + +nonlval::ConcreteInt +nonlval::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const { + assert (U->getType() == U->getSubExpr()->getType()); + assert (U->getType()->isIntegerType()); + return BasicVals.getValue(-getValue()); +} + +//===----------------------------------------------------------------------===// +// Transfer function dispatch for LVals. +//===----------------------------------------------------------------------===// + +RVal +lval::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const lval::ConcreteInt& R) const { + + assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub || + (Op >= BinaryOperator::LT && Op <= BinaryOperator::NE)); + + const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); + + if (X) + return lval::ConcreteInt(*X); + else + return UndefinedVal(); +} + +NonLVal LVal::EQ(BasicValueFactory& BasicVals, const LVal& R) const { + + switch (getSubKind()) { + default: + assert(false && "EQ not implemented for this LVal."); + break; + + case lval::ConcreteIntKind: + if (isa(R)) { + bool b = cast(this)->getValue() == + cast(R).getValue(); + + return NonLVal::MakeIntTruthVal(BasicVals, b); + } + else if (isa(R)) { + + const SymIntConstraint& C = + BasicVals.getConstraint(cast(R).getSymbol(), + BinaryOperator::EQ, + cast(this)->getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + break; + + case lval::SymbolValKind: { + if (isa(R)) { + + const SymIntConstraint& C = + BasicVals.getConstraint(cast(this)->getSymbol(), + BinaryOperator::EQ, + cast(R).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + assert (!isa(R) && "FIXME: Implement unification."); + + break; + } + + case lval::DeclValKind: + if (isa(R)) { + bool b = cast(*this) == cast(R); + return NonLVal::MakeIntTruthVal(BasicVals, b); + } + + break; + } + + return NonLVal::MakeIntTruthVal(BasicVals, false); +} + +NonLVal LVal::NE(BasicValueFactory& BasicVals, const LVal& R) const { + switch (getSubKind()) { + default: + assert(false && "NE not implemented for this LVal."); + break; + + case lval::ConcreteIntKind: + if (isa(R)) { + bool b = cast(this)->getValue() != + cast(R).getValue(); + + return NonLVal::MakeIntTruthVal(BasicVals, b); + } + else if (isa(R)) { + + const SymIntConstraint& C = + BasicVals.getConstraint(cast(R).getSymbol(), + BinaryOperator::NE, + cast(this)->getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + break; + + case lval::SymbolValKind: { + if (isa(R)) { + + const SymIntConstraint& C = + BasicVals.getConstraint(cast(this)->getSymbol(), + BinaryOperator::NE, + cast(R).getValue()); + + return nonlval::SymIntConstraintVal(C); + } + + assert (!isa(R) && "FIXME: Implement sym !=."); + + break; + } + + case lval::DeclValKind: + if (isa(R)) { + bool b = cast(*this) == cast(R); + return NonLVal::MakeIntTruthVal(BasicVals, b); + } + + break; + } + + return NonLVal::MakeIntTruthVal(BasicVals, true); +} + +//===----------------------------------------------------------------------===// +// Utility methods for constructing Non-LVals. +//===----------------------------------------------------------------------===// + +NonLVal NonLVal::MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T) { + return nonlval::ConcreteInt(BasicVals.getValue(X, T)); +} + +NonLVal NonLVal::MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I) { + + return nonlval::ConcreteInt(BasicVals.getValue(APSInt(I->getValue(), + I->getType()->isUnsignedIntegerType()))); +} + +NonLVal NonLVal::MakeIntTruthVal(BasicValueFactory& BasicVals, bool b) { + return nonlval::ConcreteInt(BasicVals.getTruthValue(b)); +} + +RVal RVal::GetSymbolValue(SymbolManager& SymMgr, VarDecl* D) { + + QualType T = D->getType(); + + if (T->isPointerType() || T->isReferenceType()) + return lval::SymbolVal(SymMgr.getSymbol(D)); + else + return nonlval::SymbolVal(SymMgr.getSymbol(D)); +} + +//===----------------------------------------------------------------------===// +// Utility methods for constructing LVals. +//===----------------------------------------------------------------------===// + +LVal LVal::MakeVal(AddrLabelExpr* E) { return lval::GotoLabel(E->getLabel()); } + +//===----------------------------------------------------------------------===// +// Utility methods for constructing RVals (both NonLVals and LVals). +//===----------------------------------------------------------------------===// + +RVal RVal::MakeVal(BasicValueFactory& BasicVals, DeclRefExpr* E) { + + ValueDecl* D = cast(E)->getDecl(); + + if (VarDecl* VD = dyn_cast(D)) { + return lval::DeclVal(VD); + } + else if (EnumConstantDecl* ED = dyn_cast(D)) { + + // FIXME: Do we need to cache a copy of this enum, since it + // already has persistent storage? We do this because we + // are comparing states using pointer equality. Perhaps there is + // a better way, since APInts are fairly lightweight. + + return nonlval::ConcreteInt(BasicVals.getValue(ED->getInitVal())); + } + else if (FunctionDecl* FD = dyn_cast(D)) { + return lval::FuncVal(FD); + } + + assert (false && + "ValueDecl support for this ValueDecl not implemented."); + + return UnknownVal(); +} + +//===----------------------------------------------------------------------===// +// Pretty-Printing. +//===----------------------------------------------------------------------===// + +void RVal::printStdErr() const { print(*llvm::cerr.stream()); } + +void RVal::print(std::ostream& Out) const { + + switch (getBaseKind()) { + + case UnknownKind: + Out << "Invalid"; break; + + case NonLValKind: + cast(this)->print(Out); break; + + case LValKind: + cast(this)->print(Out); break; + + case UndefinedKind: + Out << "Undefined"; break; + + default: + assert (false && "Invalid RVal."); + } +} + +static void printOpcode(std::ostream& Out, BinaryOperator::Opcode Op) { + + switch (Op) { + case BinaryOperator::Mul: Out << '*' ; break; + case BinaryOperator::Div: Out << '/' ; break; + case BinaryOperator::Rem: Out << '%' ; break; + case BinaryOperator::Add: Out << '+' ; break; + case BinaryOperator::Sub: Out << '-' ; break; + case BinaryOperator::Shl: Out << "<<" ; break; + case BinaryOperator::Shr: Out << ">>" ; break; + case BinaryOperator::LT: Out << "<" ; break; + case BinaryOperator::GT: Out << '>' ; break; + case BinaryOperator::LE: Out << "<=" ; break; + case BinaryOperator::GE: Out << ">=" ; break; + case BinaryOperator::EQ: Out << "==" ; break; + case BinaryOperator::NE: Out << "!=" ; break; + case BinaryOperator::And: Out << '&' ; break; + case BinaryOperator::Xor: Out << '^' ; break; + case BinaryOperator::Or: Out << '|' ; break; + + default: assert(false && "Not yet implemented."); + } +} + +void NonLVal::print(std::ostream& Out) const { + + switch (getSubKind()) { + + case nonlval::ConcreteIntKind: + Out << cast(this)->getValue().toString(); + + if (cast(this)->getValue().isUnsigned()) + Out << 'U'; + + break; + + case nonlval::SymbolValKind: + Out << '$' << cast(this)->getSymbol(); + break; + + case nonlval::SymIntConstraintValKind: { + const nonlval::SymIntConstraintVal& C = + *cast(this); + + Out << '$' << C.getConstraint().getSymbol() << ' '; + printOpcode(Out, C.getConstraint().getOpcode()); + Out << ' ' << C.getConstraint().getInt().toString(); + + if (C.getConstraint().getInt().isUnsigned()) + Out << 'U'; + + break; + } + + default: + assert (false && "Pretty-printed not implemented for this NonLVal."); + break; + } +} + +void LVal::print(std::ostream& Out) const { + + switch (getSubKind()) { + + case lval::ConcreteIntKind: + Out << cast(this)->getValue().toString() + << " (LVal)"; + break; + + case lval::SymbolValKind: + Out << '$' << cast(this)->getSymbol(); + break; + + case lval::GotoLabelKind: + Out << "&&" + << cast(this)->getLabel()->getID()->getName(); + break; + + case lval::DeclValKind: + Out << '&' + << cast(this)->getDecl()->getIdentifier()->getName(); + break; + + case lval::FuncValKind: + Out << "function " + << cast(this)->getDecl()->getIdentifier()->getName(); + break; + + default: + assert (false && "Pretty-printing not implemented for this LVal."); + break; + } +} diff --git a/clang/lib/Analysis/SymbolManager.cpp b/clang/lib/Analysis/SymbolManager.cpp new file mode 100644 index 00000000000..f243fa667b3 --- /dev/null +++ b/clang/lib/Analysis/SymbolManager.cpp @@ -0,0 +1,124 @@ +//== SymbolManager.h - Management of Symbolic Values ------------*- 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 SymbolManager, a class that manages symbolic values +// created for use by GRExprEngine and related classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/SymbolManager.h" + +using namespace clang; + +SymbolID SymbolManager::getSymbol(VarDecl* D) { + + assert (isa(D) || D->hasGlobalStorage()); + + llvm::FoldingSetNodeID profile; + + ParmVarDecl* PD = dyn_cast(D); + + if (PD) + SymbolDataParmVar::Profile(profile, PD); + else + SymbolDataGlobalVar::Profile(profile, D); + + void* InsertPos; + + SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + + if (SD) + return SD->getSymbol(); + + if (PD) { + SD = (SymbolData*) BPAlloc.Allocate(); + new (SD) SymbolDataParmVar(SymbolCounter, PD); + } + else { + SD = (SymbolData*) BPAlloc.Allocate(); + new (SD) SymbolDataGlobalVar(SymbolCounter, D); + } + + DataSet.InsertNode(SD, InsertPos); + + DataMap[SymbolCounter] = SD; + return SymbolCounter++; +} + +SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) { + + llvm::FoldingSetNodeID profile; + SymbolDataContentsOf::Profile(profile, sym); + void* InsertPos; + + SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + + if (SD) + return SD->getSymbol(); + + SD = (SymbolData*) BPAlloc.Allocate(); + new (SD) SymbolDataContentsOf(SymbolCounter, sym); + + + DataSet.InsertNode(SD, InsertPos); + DataMap[SymbolCounter] = SD; + + return SymbolCounter++; +} + +SymbolID SymbolManager::getConjuredSymbol(Expr* E, unsigned Count) { + + llvm::FoldingSetNodeID profile; + SymbolConjured::Profile(profile, E, Count); + void* InsertPos; + + SymbolData* SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + + if (SD) + return SD->getSymbol(); + + SD = (SymbolData*) BPAlloc.Allocate(); + new (SD) SymbolConjured(SymbolCounter, E, Count); + + DataSet.InsertNode(SD, InsertPos); + DataMap[SymbolCounter] = SD; + + return SymbolCounter++; +} + +const SymbolData& SymbolManager::getSymbolData(SymbolID Sym) const { + DataMapTy::const_iterator I = DataMap.find(Sym); + assert (I != DataMap.end()); + return *I->second; +} + + +QualType SymbolData::getType(const SymbolManager& SymMgr) const { + switch (getKind()) { + default: + assert (false && "getType() not implemented for this symbol."); + + case ParmKind: + return cast(this)->getDecl()->getType(); + + case GlobalKind: + return cast(this)->getDecl()->getType(); + + case ContentsOfKind: { + SymbolID x = cast(this)->getContainerSymbol(); + QualType T = SymMgr.getSymbolData(x).getType(SymMgr); + return T->getAsPointerType()->getPointeeType(); + } + + case ConjuredKind: + return cast(this)->getExpr()->getType(); + } +} + +SymbolManager::~SymbolManager() {} diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp new file mode 100644 index 00000000000..25a5ecb4837 --- /dev/null +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -0,0 +1,277 @@ +//==- UninitializedValues.cpp - Find Unintialized Values --------*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Uninitialized Values analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/UninitializedValues.h" +#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" +#include "clang/Analysis/LocalCheckers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/ASTContext.h" +#include "clang/Analysis/FlowSensitive/DataflowSolver.h" +#include "llvm/Support/Compiler.h" + +#include "llvm/ADT/SmallPtrSet.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Dataflow initialization logic. +//===----------------------------------------------------------------------===// + +namespace { + +class VISIBILITY_HIDDEN RegisterDecls + : public CFGRecStmtDeclVisitor { + + UninitializedValues::AnalysisDataTy& AD; +public: + RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} + + void VisitBlockVarDecl(BlockVarDecl* VD) { AD.Register(VD); } + CFG& getCFG() { return AD.getCFG(); } +}; + +} // end anonymous namespace + +void UninitializedValues::InitializeValues(const CFG& cfg) { + RegisterDecls R(getAnalysisData()); + cfg.VisitBlockStmts(R); +} + +//===----------------------------------------------------------------------===// +// Transfer functions. +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN TransferFuncs + : public CFGStmtVisitor { + + UninitializedValues::ValTy V; + UninitializedValues::AnalysisDataTy& AD; +public: + TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) { + V.resetValues(AD); + } + + UninitializedValues::ValTy& getVal() { return V; } + CFG& getCFG() { return AD.getCFG(); } + + bool VisitDeclRefExpr(DeclRefExpr* DR); + bool VisitBinaryOperator(BinaryOperator* B); + bool VisitUnaryOperator(UnaryOperator* U); + bool VisitStmt(Stmt* S); + bool VisitCallExpr(CallExpr* C); + bool VisitDeclStmt(DeclStmt* D); + bool VisitConditionalOperator(ConditionalOperator* C); + + bool Visit(Stmt *S); + bool BlockStmt_VisitExpr(Expr* E); + + BlockVarDecl* FindBlockVarDecl(Stmt* S); +}; + +static const bool Initialized = true; +static const bool Uninitialized = false; + +bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { + if (BlockVarDecl* VD = dyn_cast(DR->getDecl())) { + if (AD.Observer) AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD); + + // Pseudo-hack to prevent cascade of warnings. If an accessed variable + // is uninitialized, then we are already going to flag a warning for + // this variable, which a "source" of uninitialized values. + // We can otherwise do a full "taint" of uninitialized values. The + // client has both options by toggling AD.FullUninitTaint. + + return AD.FullUninitTaint ? V(VD,AD) : Initialized; + } + else return Initialized; +} + +BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) { + for (;;) + if (ParenExpr* P = dyn_cast(S)) { + S = P->getSubExpr(); continue; + } + else if (DeclRefExpr* DR = dyn_cast(S)) { + if (BlockVarDecl* VD = dyn_cast(DR->getDecl())) + return VD; + else + return NULL; + } + else return NULL; +} + +bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { + if (BlockVarDecl* VD = FindBlockVarDecl(B->getLHS())) + if (B->isAssignmentOp()) { + if (B->getOpcode() == BinaryOperator::Assign) + return V(VD,AD) = Visit(B->getRHS()); + else // Handle +=, -=, *=, etc. We do want '&', not '&&'. + return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS()); + } + + return VisitStmt(B); +} + +bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { + for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator()) + if (BlockVarDecl* VD = dyn_cast(D)) { + if (Stmt* I = VD->getInit()) + V(VD,AD) = AD.FullUninitTaint ? V(cast(I),AD) : Initialized; + else { + // Special case for declarations of array types. For things like: + // + // char x[10]; + // + // we should treat "x" as being initialized, because the variable + // "x" really refers to the memory block. Clearly x[1] is + // uninitialized, but expressions like "(char *) x" really do refer to + // an initialized value. This simple dataflow analysis does not reason + // about the contents of arrays, although it could be potentially + // extended to do so if the array were of constant size. + if (VD->getType()->isArrayType()) + V(VD,AD) = Initialized; + else + V(VD,AD) = Uninitialized; + } + } + + return Uninitialized; // Value is never consumed. +} + +bool TransferFuncs::VisitCallExpr(CallExpr* C) { + VisitChildren(C); + return Initialized; +} + +bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { + switch (U->getOpcode()) { + case UnaryOperator::AddrOf: + if (BlockVarDecl* VD = FindBlockVarDecl(U->getSubExpr())) + return V(VD,AD) = Initialized; + + break; + + case UnaryOperator::SizeOf: + return Initialized; + + default: + break; + } + + return Visit(U->getSubExpr()); +} + +bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) { + Visit(C->getCond()); + + bool rhsResult = Visit(C->getRHS()); + // Handle the GNU extension for missing LHS. + if (Expr *lhs = C->getLHS()) + return Visit(lhs) & rhsResult; // Yes: we want &, not &&. + else + return rhsResult; +} + +bool TransferFuncs::VisitStmt(Stmt* S) { + bool x = Initialized; + + // We don't stop at the first subexpression that is Uninitialized because + // evaluating some subexpressions may result in propogating "Uninitialized" + // or "Initialized" to variables referenced in the other subexpressions. + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) + if (*I && Visit(*I) == Uninitialized) x = Uninitialized; + + return x; +} + +bool TransferFuncs::Visit(Stmt *S) { + if (AD.isTracked(static_cast(S))) return V(static_cast(S),AD); + else return static_cast*>(this)->Visit(S); +} + +bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { + bool x = static_cast*>(this)->Visit(E); + if (AD.isTracked(E)) V(E,AD) = x; + return x; +} + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Merge operator. +// +// In our transfer functions we take the approach that any +// combination of unintialized values, e.g. Unitialized + ___ = Unitialized. +// +// Merges take the opposite approach. +// +// In the merge of dataflow values we prefer unsoundness, and +// prefer false negatives to false positives. At merges, if a value for a +// tracked Decl is EVER initialized in any of the predecessors we treat it as +// initialized at the confluence point. +//===----------------------------------------------------------------------===// + +namespace { + typedef ExprDeclBitVector_Types::Union Merge; + typedef DataflowSolver Solver; +} + +//===----------------------------------------------------------------------===// +// Unitialized values checker. Scan an AST and flag variable uses +//===----------------------------------------------------------------------===// + +UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} + +namespace { +class VISIBILITY_HIDDEN UninitializedValuesChecker + : public UninitializedValues::ObserverTy { + + ASTContext &Ctx; + Diagnostic &Diags; + llvm::SmallPtrSet AlreadyWarned; + +public: + UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags) + : Ctx(ctx), Diags(diags) {} + + virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V, + UninitializedValues::AnalysisDataTy& AD, + DeclRefExpr* DR, BlockVarDecl* VD) { + + assert ( AD.isTracked(VD) && "Unknown VarDecl."); + + if (V(VD,AD) == Uninitialized) + if (AlreadyWarned.insert(VD)) + Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), + diag::warn_uninit_val); + } +}; +} // end anonymous namespace + +namespace clang { +void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags, + bool FullUninitTaint) { + + // Compute the unitialized values information. + UninitializedValues U(cfg); + U.getAnalysisData().FullUninitTaint = FullUninitTaint; + Solver S(U); + S.runOnCFG(cfg); + + // Scan for DeclRefExprs that use uninitialized values. + UninitializedValuesChecker Observer(Ctx,Diags); + U.getAnalysisData().Observer = &Observer; + S.runOnAllBlocks(cfg); +} +} // end namespace clang diff --git a/clang/lib/Analysis/ValueState.cpp b/clang/lib/Analysis/ValueState.cpp new file mode 100644 index 00000000000..c0ed7aa882a --- /dev/null +++ b/clang/lib/Analysis/ValueState.cpp @@ -0,0 +1,595 @@ +//= ValueState*cpp - Path-Sens. "State" for tracking valuues -----*- 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 SymbolID, ExprBindKey, and ValueState* +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/ValueState.h" +#include "llvm/ADT/SmallSet.h" + +using namespace clang; + +bool ValueState::isNotEqual(SymbolID sym, const llvm::APSInt& V) const { + + // Retrieve the NE-set associated with the given symbol. + ConstNotEqTy::TreeTy* T = ConstNotEq.SlimFind(sym); + + // See if V is present in the NE-set. + return T ? T->getValue().second.contains(&V) : false; +} + +const llvm::APSInt* ValueState::getSymVal(SymbolID sym) const { + ConstEqTy::TreeTy* T = ConstEq.SlimFind(sym); + return T ? T->getValue().second : NULL; +} + +ValueState* +ValueStateManager::RemoveDeadBindings(ValueState* St, Stmt* Loc, + const LiveVariables& Liveness) { + + // This code essentially performs a "mark-and-sweep" of the VariableBindings. + // The roots are any Block-level exprs and Decls that our liveness algorithm + // tells us are live. We then see what Decls they may reference, and keep + // those around. This code more than likely can be made faster, and the + // frequency of which this method is called should be experimented with + // for optimum performance. + + llvm::SmallVector WList; + llvm::SmallPtrSet Marked; + llvm::SmallSet MarkedSymbols; + + ValueState NewSt = *St; + + // Drop bindings for subexpressions. + NewSt.SubExprBindings = EXFactory.GetEmptyMap(); + + // Iterate over the block-expr bindings. + + for (ValueState::beb_iterator I = St->beb_begin(), E = St->beb_end(); + I!=E ; ++I) { + Expr* BlkExpr = I.getKey(); + + if (Liveness.isLive(Loc, BlkExpr)) { + RVal X = I.getData(); + + if (isa(X)) { + lval::DeclVal LV = cast(X); + WList.push_back(LV.getDecl()); + } + + for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); + SI != SE; ++SI) { + MarkedSymbols.insert(*SI); + } + } + else { + RVal X = I.getData(); + + if (X.isUndef() && cast(X).getData()) + continue; + + NewSt.BlockExprBindings = Remove(NewSt, BlkExpr); + } + } + + // Iterate over the variable bindings. + + for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I) + if (Liveness.isLive(Loc, I.getKey())) { + WList.push_back(I.getKey()); + + RVal X = I.getData(); + + for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); + SI != SE; ++SI) { + MarkedSymbols.insert(*SI); + } + } + + // Perform the mark-and-sweep. + + while (!WList.empty()) { + + ValueDecl* V = WList.back(); + WList.pop_back(); + + if (Marked.count(V)) + continue; + + Marked.insert(V); + + if (V->getType()->isPointerType()) { + + RVal X = GetRVal(St, lval::DeclVal(cast(V))); + + if (X.isUnknownOrUndef()) + continue; + + LVal LV = cast(X); + + for (RVal::symbol_iterator SI = LV.symbol_begin(), SE = LV.symbol_end(); + SI != SE; ++SI) { + MarkedSymbols.insert(*SI); + } + + if (!isa(LV)) + continue; + + const lval::DeclVal& LVD = cast(LV); + WList.push_back(LVD.getDecl()); + } + } + + // Remove dead variable bindings. + for (ValueState::vb_iterator I = St->vb_begin(), E = St->vb_end(); I!=E ; ++I) + if (!Marked.count(I.getKey())) + NewSt.VarBindings = Remove(NewSt, I.getKey()); + + // Remove dead symbols. + for (ValueState::ce_iterator I = St->ce_begin(), E=St->ce_end(); I!=E; ++I) + if (!MarkedSymbols.count(I.getKey())) + NewSt.ConstEq = CEFactory.Remove(NewSt.ConstEq, I.getKey()); + + for (ValueState::cne_iterator I = St->cne_begin(), E=St->cne_end(); I!=E; ++I) + if (!MarkedSymbols.count(I.getKey())) + NewSt.ConstNotEq = CNEFactory.Remove(NewSt.ConstNotEq, I.getKey()); + + return getPersistentState(NewSt); +} + + +RVal ValueStateManager::GetRVal(ValueState* St, LVal LV, QualType T) { + + if (isa(LV)) + return UnknownVal(); + + assert (!isa(LV)); + + switch (LV.getSubKind()) { + case lval::DeclValKind: { + ValueState::VarBindingsTy::TreeTy* T = + St->VarBindings.SlimFind(cast(LV).getDecl()); + + return T ? T->getValue().second : UnknownVal(); + } + + // FIXME: We should limit how far a "ContentsOf" will go... + + case lval::SymbolValKind: { + + + // FIXME: This is a broken representation of memory, and is prone + // to crashing the analyzer when addresses to symbolic values are + // passed through casts. We need a better representation of symbolic + // memory (or just memory in general); probably we should do this + // as a plugin class (similar to GRTransferFuncs). + +#if 0 + const lval::SymbolVal& SV = cast(LV); + assert (T.getTypePtr()); + + // Punt on "symbolic" function pointers. + if (T->isFunctionType()) + return UnknownVal(); + + if (T->isPointerType()) + return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol())); + else + return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol())); +#endif + + return UnknownVal(); + } + + default: + assert (false && "Invalid LVal."); + break; + } + + return UnknownVal(); +} + +ValueState* ValueStateManager::AddNE(ValueState* St, SymbolID sym, + const llvm::APSInt& V) { + + // First, retrieve the NE-set associated with the given symbol. + ValueState::ConstNotEqTy::TreeTy* T = St->ConstNotEq.SlimFind(sym); + ValueState::IntSetTy S = T ? T->getValue().second : ISetFactory.GetEmptySet(); + + // Now add V to the NE set. + S = ISetFactory.Add(S, &V); + + // Create a new state with the old binding replaced. + ValueState NewSt = *St; + NewSt.ConstNotEq = CNEFactory.Add(NewSt.ConstNotEq, sym, S); + + // Get the persistent copy. + return getPersistentState(NewSt); +} + +ValueState* ValueStateManager::AddEQ(ValueState* St, SymbolID sym, + const llvm::APSInt& V) { + + // Create a new state with the old binding replaced. + ValueState NewSt = *St; + NewSt.ConstEq = CEFactory.Add(NewSt.ConstEq, sym, &V); + + // Get the persistent copy. + return getPersistentState(NewSt); +} + +RVal ValueStateManager::GetRVal(ValueState* St, Expr* E) { + + for (;;) { + + switch (E->getStmtClass()) { + + case Stmt::AddrLabelExprClass: + return LVal::MakeVal(cast(E)); + + // ParenExprs are no-ops. + + case Stmt::ParenExprClass: + E = cast(E)->getSubExpr(); + continue; + + // DeclRefExprs can either evaluate to an LVal or a Non-LVal + // (assuming an implicit "load") depending on the context. In this + // context we assume that we are retrieving the value contained + // within the referenced variables. + + case Stmt::DeclRefExprClass: { + + // Check if this expression is a block-level expression. If so, + // return its value. + ValueState::ExprBindingsTy::TreeTy* T=St->BlockExprBindings.SlimFind(E); + if (T) return T->getValue().second; + + RVal X = RVal::MakeVal(BasicVals, cast(E)); + return isa(X) ? GetRVal(St, cast(X)) : X; + } + + case Stmt::CharacterLiteralClass: { + CharacterLiteral* C = cast(E); + return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType()); + } + + case Stmt::IntegerLiteralClass: { + return NonLVal::MakeVal(BasicVals, cast(E)); + } + + // Casts where the source and target type are the same + // are no-ops. We blast through these to get the descendant + // subexpression that has a value. + + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr* C = cast(E); + QualType CT = C->getType(); + + if (CT->isVoidType()) + return UnknownVal(); + + QualType ST = C->getSubExpr()->getType(); + + if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { + E = C->getSubExpr(); + continue; + } + + break; + } + + case Stmt::CastExprClass: { + CastExpr* C = cast(E); + QualType CT = C->getType(); + QualType ST = C->getSubExpr()->getType(); + + if (CT->isVoidType()) + return UnknownVal(); + + if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { + E = C->getSubExpr(); + continue; + } + + break; + } + + case Stmt::UnaryOperatorClass: { + + UnaryOperator* U = cast(E); + + if (U->getOpcode() == UnaryOperator::Plus) { + E = U->getSubExpr(); + continue; + } + + break; + } + + // Handle all other Expr* using a lookup. + + default: + break; + }; + + break; + } + + ValueState::ExprBindingsTy::TreeTy* T = St->SubExprBindings.SlimFind(E); + + if (T) + return T->getValue().second; + + T = St->BlockExprBindings.SlimFind(E); + return T ? T->getValue().second : UnknownVal(); +} + +RVal ValueStateManager::GetBlkExprRVal(ValueState* St, Expr* E) { + + E = E->IgnoreParens(); + + switch (E->getStmtClass()) { + case Stmt::CharacterLiteralClass: { + CharacterLiteral* C = cast(E); + return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType()); + } + + case Stmt::IntegerLiteralClass: { + return NonLVal::MakeVal(BasicVals, cast(E)); + } + + default: { + ValueState::ExprBindingsTy::TreeTy* T = St->BlockExprBindings.SlimFind(E); + return T ? T->getValue().second : UnknownVal(); + } + } +} + +RVal ValueStateManager::GetLVal(ValueState* St, Expr* E) { + + E = E->IgnoreParens(); + + if (DeclRefExpr* DR = dyn_cast(E)) { + ValueDecl* VD = DR->getDecl(); + + if (FunctionDecl* FD = dyn_cast(VD)) + return lval::FuncVal(FD); + else + return lval::DeclVal(cast(DR->getDecl())); + } + + if (UnaryOperator* U = dyn_cast(E)) + if (U->getOpcode() == UnaryOperator::Deref) { + E = U->getSubExpr()->IgnoreParens(); + + if (DeclRefExpr* DR = dyn_cast(E)) { + lval::DeclVal X(cast(DR->getDecl())); + return GetRVal(St, X); + } + else + return GetRVal(St, E); + } + + return GetRVal(St, E); +} + +ValueState* +ValueStateManager::SetRVal(ValueState* St, Expr* E, RVal V, + bool isBlkExpr, bool Invalidate) { + + assert (E); + + if (V.isUnknown()) { + + if (Invalidate) { + + ValueState NewSt = *St; + + if (isBlkExpr) + NewSt.BlockExprBindings = EXFactory.Remove(NewSt.BlockExprBindings, E); + else + NewSt.SubExprBindings = EXFactory.Remove(NewSt.SubExprBindings, E); + + return getPersistentState(NewSt); + } + + return St; + } + + ValueState NewSt = *St; + + if (isBlkExpr) { + NewSt.BlockExprBindings = EXFactory.Add(NewSt.BlockExprBindings, E, V); + } + else { + NewSt.SubExprBindings = EXFactory.Add(NewSt.SubExprBindings, E, V); + } + + return getPersistentState(NewSt); +} + + +ValueState* ValueStateManager::SetRVal(ValueState* St, LVal LV, RVal V) { + + switch (LV.getSubKind()) { + + case lval::DeclValKind: + return V.isUnknown() + ? UnbindVar(St, cast(LV).getDecl()) + : BindVar(St, cast(LV).getDecl(), V); + + default: + assert ("SetRVal for given LVal type not yet implemented."); + return St; + } +} + +void ValueStateManager::BindVar(ValueState& StImpl, VarDecl* D, RVal V) { + StImpl.VarBindings = VBFactory.Add(StImpl.VarBindings, D, V); +} + +ValueState* ValueStateManager::BindVar(ValueState* St, VarDecl* D, RVal V) { + + // Create a new state with the old binding removed. + ValueState NewSt = *St; + NewSt.VarBindings = VBFactory.Add(NewSt.VarBindings, D, V); + + // Get the persistent copy. + return getPersistentState(NewSt); +} + +ValueState* ValueStateManager::UnbindVar(ValueState* St, VarDecl* D) { + + // Create a new state with the old binding removed. + ValueState NewSt = *St; + NewSt.VarBindings = VBFactory.Remove(NewSt.VarBindings, D); + + // Get the persistent copy. + return getPersistentState(NewSt); +} + +void ValueStateManager::Unbind(ValueState& StImpl, LVal LV) { + + if (isa(LV)) + StImpl.VarBindings = VBFactory.Remove(StImpl.VarBindings, + cast(LV).getDecl()); + +} + +ValueState* ValueStateManager::getInitialState() { + + // Create a state with empty variable bindings. + ValueState StateImpl(EXFactory.GetEmptyMap(), + VBFactory.GetEmptyMap(), + CNEFactory.GetEmptyMap(), + CEFactory.GetEmptyMap()); + + return getPersistentState(StateImpl); +} + +ValueState* ValueStateManager::getPersistentState(ValueState& State) { + + llvm::FoldingSetNodeID ID; + State.Profile(ID); + void* InsertPos; + + if (ValueState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos)) + return I; + + ValueState* I = (ValueState*) Alloc.Allocate(); + new (I) ValueState(State); + StateSet.InsertNode(I, InsertPos); + return I; +} + +void ValueState::printDOT(std::ostream& Out, CheckerStatePrinter* P) const { + print(Out, P, "\\l", "\\|"); +} + +void ValueState::printStdErr(CheckerStatePrinter* P) const { + print(*llvm::cerr, P); +} + +void ValueState::print(std::ostream& Out, CheckerStatePrinter* P, + const char* nl, const char* sep) const { + + // Print Variable Bindings + Out << "Variables:" << nl; + + bool isFirst = true; + + for (vb_iterator I = vb_begin(), E = vb_end(); I != E; ++I) { + + if (isFirst) isFirst = false; + else Out << nl; + + Out << ' ' << I.getKey()->getName() << " : "; + I.getData().print(Out); + } + + // Print Subexpression bindings. + + isFirst = true; + + for (seb_iterator I = seb_begin(), E = seb_end(); I != E; ++I) { + + if (isFirst) { + Out << nl << nl << "Sub-Expressions:" << nl; + isFirst = false; + } + else { Out << nl; } + + Out << " (" << (void*) I.getKey() << ") "; + I.getKey()->printPretty(Out); + Out << " : "; + I.getData().print(Out); + } + + // Print block-expression bindings. + + isFirst = true; + + for (beb_iterator I = beb_begin(), E = beb_end(); I != E; ++I) { + + if (isFirst) { + Out << nl << nl << "Block-level Expressions:" << nl; + isFirst = false; + } + else { Out << nl; } + + Out << " (" << (void*) I.getKey() << ") "; + I.getKey()->printPretty(Out); + Out << " : "; + I.getData().print(Out); + } + + // Print equality constraints. + + if (!ConstEq.isEmpty()) { + + Out << nl << sep << "'==' constraints:"; + + for (ConstEqTy::iterator I = ConstEq.begin(), + E = ConstEq.end(); I!=E; ++I) { + + Out << nl << " $" << I.getKey() + << " : " << I.getData()->toString(); + } + } + + // Print != constraints. + + if (!ConstNotEq.isEmpty()) { + + Out << nl << sep << "'!=' constraints:"; + + for (ConstNotEqTy::iterator I = ConstNotEq.begin(), + EI = ConstNotEq.end(); I != EI; ++I) { + + Out << nl << " $" << I.getKey() << " : "; + isFirst = true; + + IntSetTy::iterator J = I.getData().begin(), EJ = I.getData().end(); + + for ( ; J != EJ; ++J) { + if (isFirst) isFirst = false; + else Out << ", "; + + Out << (*J)->toString(); + } + } + } + + // Print checker-specific data. + + if (P && CheckerState) + P->PrintCheckerState(Out, CheckerState, nl, sep); +} diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp new file mode 100644 index 00000000000..f62b8f126cd --- /dev/null +++ b/clang/lib/Basic/Diagnostic.cpp @@ -0,0 +1,232 @@ +//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include +#include +#include +#include +using namespace clang; + +//===----------------------------------------------------------------------===// +// Builtin Diagnostic information +//===----------------------------------------------------------------------===// + +/// Flag values for diagnostics. +enum { + // Diagnostic classes. + NOTE = 0x01, + WARNING = 0x02, + EXTENSION = 0x03, + ERROR = 0x04, + class_mask = 0x07 +}; + +/// DiagnosticFlags - A set of flags, or'd together, that describe the +/// diagnostic. +static unsigned char DiagnosticFlags[] = { +#define DIAG(ENUM,FLAGS,DESC) FLAGS, +#include "clang/Basic/DiagnosticKinds.def" + 0 +}; + +/// getDiagClass - Return the class field of the diagnostic. +/// +static unsigned getBuiltinDiagClass(unsigned DiagID) { + assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && + "Diagnostic ID out of range!"); + return DiagnosticFlags[DiagID] & class_mask; +} + +/// DiagnosticText - An english message to print for the diagnostic. These +/// should be localized. +static const char * const DiagnosticText[] = { +#define DIAG(ENUM,FLAGS,DESC) DESC, +#include "clang/Basic/DiagnosticKinds.def" + 0 +}; + +//===----------------------------------------------------------------------===// +// Custom Diagnostic information +//===----------------------------------------------------------------------===// + +namespace clang { + namespace diag { + class CustomDiagInfo { + typedef std::pair DiagDesc; + std::vector DiagInfo; + std::map DiagIDs; + public: + + /// getDescription - Return the description of the specified custom + /// diagnostic. + const char *getDescription(unsigned DiagID) const { + assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str(); + } + + /// getLevel - Return the level of the specified custom diagnostic. + Diagnostic::Level getLevel(unsigned DiagID) const { + assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first; + } + + unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) { + DiagDesc D(L, Message); + // Check to see if it already exists. + std::map::iterator I = DiagIDs.lower_bound(D); + if (I != DiagIDs.end() && I->first == D) + return I->second; + + // If not, assign a new ID. + unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS; + DiagIDs.insert(std::make_pair(D, ID)); + DiagInfo.push_back(D); + return ID; + } + }; + + } // end diag namespace +} // end clang namespace + + +//===----------------------------------------------------------------------===// +// Common Diagnostic implementation +//===----------------------------------------------------------------------===// + +Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { + WarningsAsErrors = false; + WarnOnExtensions = false; + ErrorOnExtensions = false; + // Clear all mappings, setting them to MAP_DEFAULT. + memset(DiagMappings, 0, sizeof(DiagMappings)); + + ErrorOccurred = false; + NumDiagnostics = 0; + NumErrors = 0; + CustomDiagInfo = 0; +} + +Diagnostic::~Diagnostic() { + delete CustomDiagInfo; +} + +/// getCustomDiagID - Return an ID for a diagnostic with the specified message +/// and level. If this is the first request for this diagnosic, it is +/// registered and created, otherwise the existing ID is returned. +unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { + if (CustomDiagInfo == 0) + CustomDiagInfo = new diag::CustomDiagInfo(); + return CustomDiagInfo->getOrCreateDiagID(L, Message); +} + + +/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic +/// level of the specified diagnostic ID is a Note, Warning, or Extension. +/// Note that this only works on builtin diagnostics, not custom ones. +bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { + return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && + getBuiltinDiagClass(DiagID) < ERROR; +} + + +/// getDescription - Given a diagnostic ID, return a description of the +/// issue. +const char *Diagnostic::getDescription(unsigned DiagID) { + if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) + return DiagnosticText[DiagID]; + else + return CustomDiagInfo->getDescription(DiagID); +} + +/// getDiagnosticLevel - Based on the way the client configured the Diagnostic +/// object, classify the specified diagnostic ID into a Level, consumable by +/// the DiagnosticClient. +Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { + // Handle custom diagnostics, which cannot be mapped. + if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) + return CustomDiagInfo->getLevel(DiagID); + + unsigned DiagClass = getBuiltinDiagClass(DiagID); + + // Specific non-error diagnostics may be mapped to various levels from ignored + // to error. + if (DiagClass < ERROR) { + switch (getDiagnosticMapping((diag::kind)DiagID)) { + case diag::MAP_DEFAULT: break; + case diag::MAP_IGNORE: return Ignored; + case diag::MAP_WARNING: DiagClass = WARNING; break; + case diag::MAP_ERROR: DiagClass = ERROR; break; + } + } + + // Map diagnostic classes based on command line argument settings. + if (DiagClass == EXTENSION) { + if (ErrorOnExtensions) + DiagClass = ERROR; + else if (WarnOnExtensions) + DiagClass = WARNING; + else + return Ignored; + } + + // If warnings are to be treated as errors, indicate this as such. + if (DiagClass == WARNING && WarningsAsErrors) + DiagClass = ERROR; + + switch (DiagClass) { + default: assert(0 && "Unknown diagnostic class!"); + case NOTE: return Diagnostic::Note; + case WARNING: return Diagnostic::Warning; + case ERROR: return Diagnostic::Error; + } +} + +/// Report - Issue the message to the client. If the client wants us to stop +/// compilation, return true, otherwise return false. DiagID is a member of +/// the diag::kind enum. +void Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID, + const std::string *Strs, unsigned NumStrs, + const SourceRange *Ranges, unsigned NumRanges) { + + // Figure out the diagnostic level of this message. + Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID); + + // If the client doesn't care about this message, don't issue it. + if (DiagLevel == Diagnostic::Ignored) + return; + + // If this is not an error and we are in a system header, ignore it. We have + // to check on the original class here, because we also want to ignore + // extensions and warnings in -Werror and -pedantic-errors modes, which *map* + // warnings/extensions to errors. + if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && + getBuiltinDiagClass(DiagID) != ERROR && + Client.isInSystemHeader(Pos)) + return; + + if (DiagLevel >= Diagnostic::Error) { + ErrorOccurred = true; + ++NumErrors; + } + + // Finally, report it. + Client.HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID, + Strs, NumStrs, Ranges, NumRanges); + ++NumDiagnostics; +} + +DiagnosticClient::~DiagnosticClient() {} diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp new file mode 100644 index 00000000000..cfc08ed084b --- /dev/null +++ b/clang/lib/Basic/FileManager.cpp @@ -0,0 +1,275 @@ +///===--- FileManager.cpp - File System Probing and Caching ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the FileManager interface. +// +//===----------------------------------------------------------------------===// +// +// TODO: This should index all interesting directories with dirent calls. +// getdirentries ? +// opendir/readdir_r/closedir ? +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/Streams.h" +#include "llvm/Config/config.h" +using namespace clang; + +// FIXME: Enhance libsystem to support inode and other fields. +#include + +#if defined(_MSC_VER) +#define S_ISDIR(s) (_S_IFDIR & s) +#endif + +/// NON_EXISTENT_DIR - A special value distinct from null that is used to +/// represent a dir name that doesn't exist on the disk. +#define NON_EXISTENT_DIR reinterpret_cast((intptr_t)-1) + +#ifdef LLVM_ON_WIN32 + +#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\') + +namespace { + static std::string GetFullPath(const char *relPath) + { + char *absPathStrPtr = _fullpath(NULL, relPath, 0); + assert(absPathStrPtr && "_fullpath() returned NULL!"); + + std::string absPath(absPathStrPtr); + + free(absPathStrPtr); + return absPath; + } +} + +class FileManager::UniqueDirContainer { + /// UniqueDirs - Cache from full path to existing directories/files. + /// + llvm::StringMap UniqueDirs; + +public: + DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { + std::string FullPath(GetFullPath(Name)); + return UniqueDirs.GetOrCreateValue( + FullPath.c_str(), + FullPath.c_str() + FullPath.size() + ).getValue(); + } + + size_t size() { return UniqueDirs.size(); } +}; + +class FileManager::UniqueFileContainer { + /// UniqueFiles - Cache from full path to existing directories/files. + /// + llvm::StringMap UniqueFiles; + +public: + FileEntry &getFile(const char *Name, struct stat &StatBuf) { + std::string FullPath(GetFullPath(Name)); + return UniqueFiles.GetOrCreateValue( + FullPath.c_str(), + FullPath.c_str() + FullPath.size() + ).getValue(); + } + + size_t size() { return UniqueFiles.size(); } +}; + +#else + +#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/') + +class FileManager::UniqueDirContainer { + /// UniqueDirs - Cache from ID's to existing directories/files. + /// + std::map, DirectoryEntry> UniqueDirs; + +public: + DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { + return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; + } + + size_t size() { return UniqueDirs.size(); } +}; + +class FileManager::UniqueFileContainer { + /// UniqueFiles - Cache from ID's to existing directories/files. + /// + std::set UniqueFiles; + +public: + FileEntry &getFile(const char *Name, struct stat &StatBuf) { + return + const_cast( + *UniqueFiles.insert(FileEntry(StatBuf.st_dev, + StatBuf.st_ino)).first); + } + + size_t size() { return UniqueFiles.size(); } +}; + +#endif + + +FileManager::FileManager() : UniqueDirs(*new UniqueDirContainer), + UniqueFiles(*new UniqueFileContainer), + DirEntries(64), FileEntries(64), NextFileUID(0) +{ + NumDirLookups = NumFileLookups = 0; + NumDirCacheMisses = NumFileCacheMisses = 0; +} + +FileManager::~FileManager() { + delete &UniqueDirs; + delete &UniqueFiles; +} + + +/// getDirectory - Lookup, cache, and verify the specified directory. This +/// returns null if the directory doesn't exist. +/// +const DirectoryEntry *FileManager::getDirectory(const char *NameStart, + const char *NameEnd) { + ++NumDirLookups; + llvm::StringMapEntry &NamedDirEnt = + DirEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedDirEnt.getValue()) + return NamedDirEnt.getValue() == NON_EXISTENT_DIR + ? 0 : NamedDirEnt.getValue(); + + ++NumDirCacheMisses; + + // By default, initialize it to invalid. + NamedDirEnt.setValue(NON_EXISTENT_DIR); + + // Get the null-terminated directory name as stored as the key of the + // DirEntries map. + const char *InterndDirName = NamedDirEnt.getKeyData(); + + // Check to see if the directory exists. + struct stat StatBuf; + if (stat(InterndDirName, &StatBuf) || // Error stat'ing. + !S_ISDIR(StatBuf.st_mode)) // Not a directory? + return 0; + + // It exists. See if we have already opened a directory with the same inode. + // This occurs when one dir is symlinked to another, for example. + DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); + + NamedDirEnt.setValue(&UDE); + if (UDE.getName()) // Already have an entry with this inode, return it. + return &UDE; + + // Otherwise, we don't have this directory yet, add it. We use the string + // key from the DirEntries map as the string. + UDE.Name = InterndDirName; + return &UDE; +} + +/// NON_EXISTENT_FILE - A special value distinct from null that is used to +/// represent a filename that doesn't exist on the disk. +#define NON_EXISTENT_FILE reinterpret_cast((intptr_t)-1) + +/// getFile - Lookup, cache, and verify the specified file. This returns null +/// if the file doesn't exist. +/// +const FileEntry *FileManager::getFile(const char *NameStart, + const char *NameEnd) { + ++NumFileLookups; + + // See if there is already an entry in the map. + llvm::StringMapEntry &NamedFileEnt = + FileEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedFileEnt.getValue()) + return NamedFileEnt.getValue() == NON_EXISTENT_FILE + ? 0 : NamedFileEnt.getValue(); + + ++NumFileCacheMisses; + + // By default, initialize it to invalid. + NamedFileEnt.setValue(NON_EXISTENT_FILE); + + // Figure out what directory it is in. If the string contains a / in it, + // strip off everything after it. + // FIXME: this logic should be in sys::Path. + const char *SlashPos = NameEnd-1; + while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) + --SlashPos; + + const DirectoryEntry *DirInfo; + if (SlashPos < NameStart) { + // Use the current directory if file has no path component. + const char *Name = "."; + DirInfo = getDirectory(Name, Name+1); + } else if (SlashPos == NameEnd-1) + return 0; // If filename ends with a /, it's a directory. + else + DirInfo = getDirectory(NameStart, SlashPos); + + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + // Get the null-terminated file name as stored as the key of the + // FileEntries map. + const char *InterndFileName = NamedFileEnt.getKeyData(); + + // FIXME: Use the directory info to prune this, before doing the stat syscall. + // FIXME: This will reduce the # syscalls. + + // Nope, there isn't. Check to see if the file exists. + struct stat StatBuf; + //llvm::cerr << "STATING: " << Filename; + if (stat(InterndFileName, &StatBuf) || // Error stat'ing. + S_ISDIR(StatBuf.st_mode)) { // A directory? + // If this file doesn't exist, we leave a null in FileEntries for this path. + //llvm::cerr << ": Not existing\n"; + return 0; + } + //llvm::cerr << ": exists\n"; + + // It exists. See if we have already opened a file with the same inode. + // This occurs when one dir is symlinked to another, for example. + FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); + + NamedFileEnt.setValue(&UFE); + if (UFE.getName()) // Already have an entry with this inode, return it. + return &UFE; + + // Otherwise, we don't have this directory yet, add it. + // FIXME: Change the name to be a char* that points back to the 'FileEntries' + // key. + UFE.Name = InterndFileName; + UFE.Size = StatBuf.st_size; + UFE.ModTime = StatBuf.st_mtime; + UFE.Dir = DirInfo; + UFE.UID = NextFileUID++; + return &UFE; +} + +void FileManager::PrintStats() const { + llvm::cerr << "\n*** File Manager Stats:\n"; + llvm::cerr << UniqueFiles.size() << " files found, " + << UniqueDirs.size() << " dirs found.\n"; + llvm::cerr << NumDirLookups << " dir lookups, " + << NumDirCacheMisses << " dir cache misses.\n"; + llvm::cerr << NumFileLookups << " file lookups, " + << NumFileCacheMisses << " file cache misses.\n"; + + //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups; +} diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp new file mode 100644 index 00000000000..65e984a0f78 --- /dev/null +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,551 @@ +//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IdentifierInfo, IdentifierVisitor, and +// IdentifierTable interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// IdentifierInfo Implementation +//===----------------------------------------------------------------------===// + +IdentifierInfo::IdentifierInfo() { + TokenID = tok::identifier; + ObjCID = tok::objc_not_keyword; + BuiltinID = 0; + HasMacro = false; + IsExtension = false; + IsPoisoned = false; + IsCPPOperatorKeyword = false; + FETokenInfo = 0; +} + +//===----------------------------------------------------------------------===// +// IdentifierTable Implementation +//===----------------------------------------------------------------------===// + +IdentifierTable::IdentifierTable(const LangOptions &LangOpts) + // Start with space for 8K identifiers. + : HashTable(8192) { + + // Populate the identifier table with info about keywords for the current + // language. + AddKeywords(LangOpts); +} + +// This cstor is intended to be used only for serialization. +IdentifierTable::IdentifierTable() : HashTable(8192) {} + +//===----------------------------------------------------------------------===// +// Language Keyword Implementation +//===----------------------------------------------------------------------===// + +/// AddKeyword - This method is used to associate a token ID with specific +/// 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 +/// 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 +/// specified language. +static void AddKeyword(const char *Keyword, unsigned KWLen, + tok::TokenKind TokenCode, + int C90, int C99, int CXX, int CXX0x, int BoolSupport, + const LangOptions &LangOpts, IdentifierTable &Table) { + int Flags = 0; + if (BoolSupport != 0) { + Flags = LangOpts.Boolean ? BoolSupport : 2; + } else if (LangOpts.CPlusPlus) { + Flags = LangOpts.CPlusPlus0x ? CXX0x : CXX; + } else if (LangOpts.C99) { + Flags = C99; + } else { + Flags = C90; + } + + // Don't add this keyword if disabled in this language or if an extension + // and extensions are disabled. + if (Flags + LangOpts.NoExtensions >= 2) return; + + IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen); + Info.setTokenID(TokenCode); + Info.setIsExtensionToken(Flags == 1); +} + +static void AddAlias(const char *Keyword, unsigned KWLen, + tok::TokenKind AliaseeID, + const char *AliaseeKeyword, unsigned AliaseeKWLen, + const LangOptions &LangOpts, IdentifierTable &Table) { + IdentifierInfo &AliasInfo = Table.get(Keyword, Keyword+KWLen); + IdentifierInfo &AliaseeInfo = Table.get(AliaseeKeyword, + AliaseeKeyword+AliaseeKWLen); + AliasInfo.setTokenID(AliaseeID); + AliasInfo.setIsExtensionToken(AliaseeInfo.isExtensionToken()); +} + +/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative +/// representations. +static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, + tok::TokenKind TokenCode, + IdentifierTable &Table) { + IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); + Info.setTokenID(TokenCode); + Info.setIsCPlusPlusOperatorKeyword(); +} + +/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or +/// "property". +static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, + const char *Name, unsigned NameLen, + IdentifierTable &Table) { + Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID); +} + +/// AddKeywords - Add all keywords to the symbol table. +/// +void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { + enum { + C90Shift = 0, + EXTC90 = 1 << C90Shift, + NOTC90 = 2 << C90Shift, + C99Shift = 2, + EXTC99 = 1 << C99Shift, + NOTC99 = 2 << C99Shift, + CPPShift = 4, + EXTCPP = 1 << CPPShift, + NOTCPP = 2 << CPPShift, + CPP0xShift = 6, + EXTCPP0x = 1 << CPP0xShift, + NOTCPP0x = 2 << CPP0xShift, + BoolShift = 8, + BOOLSUPPORT = 1 << BoolShift, + Mask = 3 + }; + + // Add keywords and tokens for the current language. +#define KEYWORD(NAME, FLAGS) \ + AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \ + ((FLAGS) >> C90Shift) & Mask, \ + ((FLAGS) >> C99Shift) & Mask, \ + ((FLAGS) >> CPPShift) & Mask, \ + ((FLAGS) >> CPP0xShift) & Mask, \ + ((FLAGS) >> BoolShift) & Mask, LangOpts, *this); +#define ALIAS(NAME, TOK) \ + AddAlias(NAME, strlen(NAME), tok::kw_ ## TOK, #TOK, strlen(#TOK), \ + LangOpts, *this); +#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ + if (LangOpts.CXXOperatorNames) \ + AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this); +#define OBJC1_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC1) \ + AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); +#define OBJC2_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC2) \ + AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); +#include "clang/Basic/TokenKinds.def" +} + +tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { + // We use a perfect hash function here involving the length of the keyword, + // the first and third character. For preprocessor ID's there are no + // collisions (if there were, the switch below would complain about duplicate + // case values). Note that this depends on 'if' being null terminated. + +#define HASH(LEN, FIRST, THIRD) \ + (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) +#define CASE(LEN, FIRST, THIRD, NAME) \ + case HASH(LEN, FIRST, THIRD): \ + return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME + + unsigned Len = getLength(); + if (Len < 2) return tok::pp_not_keyword; + const char *Name = getName(); + switch (HASH(Len, Name[0], Name[2])) { + default: return tok::pp_not_keyword; + CASE( 2, 'i', '\0', if); + CASE( 4, 'e', 'i', elif); + CASE( 4, 'e', 's', else); + CASE( 4, 'l', 'n', line); + CASE( 4, 's', 'c', sccs); + CASE( 5, 'e', 'd', endif); + CASE( 5, 'e', 'r', error); + CASE( 5, 'i', 'e', ident); + CASE( 5, 'i', 'd', ifdef); + CASE( 5, 'u', 'd', undef); + + CASE( 6, 'a', 's', assert); + CASE( 6, 'd', 'f', define); + CASE( 6, 'i', 'n', ifndef); + CASE( 6, 'i', 'p', import); + CASE( 6, 'p', 'a', pragma); + + CASE( 7, 'd', 'f', defined); + CASE( 7, 'i', 'c', include); + CASE( 7, 'w', 'r', warning); + + CASE( 8, 'u', 'a', unassert); + CASE(12, 'i', 'c', include_next); +#undef CASE +#undef HASH + } +} + +//===----------------------------------------------------------------------===// +// Stats Implementation +//===----------------------------------------------------------------------===// + +/// PrintStats - Print statistics about how well the identifier table is doing +/// at hashing identifiers. +void IdentifierTable::PrintStats() const { + unsigned NumBuckets = HashTable.getNumBuckets(); + unsigned NumIdentifiers = HashTable.getNumItems(); + unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers; + unsigned AverageIdentifierSize = 0; + unsigned MaxIdentifierLength = 0; + + // TODO: Figure out maximum times an identifier had to probe for -stats. + for (llvm::StringMap::const_iterator + I = HashTable.begin(), E = HashTable.end(); I != E; ++I) { + unsigned IdLen = I->getKeyLength(); + AverageIdentifierSize += IdLen; + if (MaxIdentifierLength < IdLen) + MaxIdentifierLength = IdLen; + } + + fprintf(stderr, "\n*** Identifier Table Stats:\n"); + fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers); + fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets); + fprintf(stderr, "Hash density (#identifiers per bucket): %f\n", + NumIdentifiers/(double)NumBuckets); + fprintf(stderr, "Ave identifier length: %f\n", + (AverageIdentifierSize/(double)NumIdentifiers)); + fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength); + + // Compute statistics about the memory allocated for identifiers. + HashTable.getAllocator().PrintStats(); +} + +//===----------------------------------------------------------------------===// +// SelectorTable Implementation +//===----------------------------------------------------------------------===// + +unsigned llvm::DenseMapInfo::getHashValue(clang::Selector S) { + return DenseMapInfo::getHashValue(S.getAsOpaquePtr()); +} + + +/// MultiKeywordSelector - One of these variable length records is kept for each +/// selector containing more than one keyword. We use a folding set +/// to unique aggregate names (keyword selectors in ObjC parlance). Access to +/// this class is provided strictly through Selector. +namespace clang { +class MultiKeywordSelector : public llvm::FoldingSetNode { + friend SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer&); + MultiKeywordSelector(unsigned nKeys) : NumArgs(nKeys) {} +public: + unsigned NumArgs; + + // Constructor for keyword selectors. + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { + assert((nKeys > 1) && "not a multi-keyword selector"); + NumArgs = nKeys; + + // Fill in the trailing keyword array. + IdentifierInfo **KeyInfo = reinterpret_cast(this+1); + for (unsigned i = 0; i != nKeys; ++i) + KeyInfo[i] = IIV[i]; + } + + // getName - Derive the full selector name and return it. + std::string getName() const; + + unsigned getNumArgs() const { return NumArgs; } + + typedef IdentifierInfo *const *keyword_iterator; + keyword_iterator keyword_begin() const { + return reinterpret_cast(this+1); + } + keyword_iterator keyword_end() const { + return keyword_begin()+NumArgs; + } + IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { + assert(i < NumArgs && "getIdentifierInfoForSlot(): illegal index"); + return keyword_begin()[i]; + } + static void Profile(llvm::FoldingSetNodeID &ID, + keyword_iterator ArgTys, unsigned NumArgs) { + ID.AddInteger(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i]); + } + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, keyword_begin(), NumArgs); + } +}; +} // end namespace clang. + +unsigned Selector::getNumArgs() const { + unsigned IIF = getIdentifierInfoFlag(); + if (IIF == ZeroArg) + return 0; + if (IIF == OneArg) + return 1; + // We point to a MultiKeywordSelector (pointer doesn't contain any flags). + MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); + return SI->getNumArgs(); +} + +IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { + if (IdentifierInfo *II = getAsIdentifierInfo()) { + assert(argIndex == 0 && "illegal keyword index"); + return II; + } + // We point to a MultiKeywordSelector (pointer doesn't contain any flags). + MultiKeywordSelector *SI = reinterpret_cast(InfoPtr); + return SI->getIdentifierInfoForSlot(argIndex); +} + +std::string MultiKeywordSelector::getName() const { + std::string Result; + unsigned Length = 0; + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + Length += (*I)->getLength(); + ++Length; // : + } + + Result.reserve(Length); + + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + Result.insert(Result.end(), (*I)->getName(), + (*I)->getName()+(*I)->getLength()); + Result.push_back(':'); + } + + return Result; +} + +std::string Selector::getName() const { + if (IdentifierInfo *II = getAsIdentifierInfo()) { + if (getNumArgs() == 0) + return II->getName(); + + std::string Res = II->getName(); + Res += ":"; + return Res; + } + + // We have a multiple keyword selector (no embedded flags). + return reinterpret_cast(InfoPtr)->getName(); +} + + +Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { + if (nKeys < 2) + return Selector(IIV[0], nKeys); + + llvm::FoldingSet *SelTab; + + SelTab = static_cast *>(Impl); + + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + MultiKeywordSelector::Profile(ID, IIV, nKeys); + + void *InsertPos = 0; + if (MultiKeywordSelector *SI = SelTab->FindNodeOrInsertPos(ID, InsertPos)) + return Selector(SI); + + // MultiKeywordSelector objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + MultiKeywordSelector *SI = + (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + + nKeys*sizeof(IdentifierInfo *)); + new (SI) MultiKeywordSelector(nKeys, IIV); + SelTab->InsertNode(SI, InsertPos); + return Selector(SI); +} + +SelectorTable::SelectorTable() { + Impl = new llvm::FoldingSet; +} + +SelectorTable::~SelectorTable() { + delete static_cast *>(Impl); +} + +//===----------------------------------------------------------------------===// +// Serialization for IdentifierInfo and IdentifierTable. +//===----------------------------------------------------------------------===// + +void IdentifierInfo::Emit(llvm::Serializer& S) const { + S.EmitInt(getTokenID()); + S.EmitInt(getBuiltinID()); + S.EmitInt(getObjCKeywordID()); + S.EmitBool(hasMacroDefinition()); + S.EmitBool(isExtensionToken()); + S.EmitBool(isPoisoned()); + S.EmitBool(isCPlusPlusOperatorKeyword()); + // FIXME: FETokenInfo +} + +void IdentifierInfo::Read(llvm::Deserializer& D) { + setTokenID((tok::TokenKind) D.ReadInt()); + setBuiltinID(D.ReadInt()); + setObjCKeywordID((tok::ObjCKeywordKind) D.ReadInt()); + setHasMacroDefinition(D.ReadBool()); + setIsExtensionToken(D.ReadBool()); + setIsPoisoned(D.ReadBool()); + setIsCPlusPlusOperatorKeyword(D.ReadBool()); + // FIXME: FETokenInfo +} + +void IdentifierTable::Emit(llvm::Serializer& S) const { + S.EnterBlock(); + + S.EmitPtr(this); + + for (iterator I=begin(), E=end(); I != E; ++I) { + const char* Key = I->getKeyData(); + const IdentifierInfo* Info = &I->getValue(); + + bool KeyRegistered = S.isRegistered(Key); + bool InfoRegistered = S.isRegistered(Info); + + if (KeyRegistered || InfoRegistered) { + // These acrobatics are so that we don't incur the cost of registering + // a pointer with the backpatcher during deserialization if nobody + // references the object. + S.EmitPtr(InfoRegistered ? Info : NULL); + S.EmitPtr(KeyRegistered ? Key : NULL); + S.EmitCStr(Key); + S.Emit(*Info); + } + } + + S.ExitBlock(); +} + +IdentifierTable* IdentifierTable::CreateAndRegister(llvm::Deserializer& D) { + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + + std::vector buff; + buff.reserve(200); + + IdentifierTable* t = new IdentifierTable(); + D.RegisterPtr(t); + + while (!D.FinishedBlock(BLoc)) { + llvm::SerializedPtrID InfoPtrID = D.ReadPtrID(); + llvm::SerializedPtrID KeyPtrID = D.ReadPtrID(); + + D.ReadCStr(buff); + + llvm::StringMapEntry& Entry = + t->HashTable.GetOrCreateValue(&buff[0],&buff[0]+buff.size()); + + D.Read(Entry.getValue()); + + if (InfoPtrID) + D.RegisterRef(InfoPtrID,Entry.getValue()); + + if (KeyPtrID) + D.RegisterPtr(KeyPtrID,Entry.getKeyData()); + } + + return t; +} + +//===----------------------------------------------------------------------===// +// Serialization for Selector and SelectorTable. +//===----------------------------------------------------------------------===// + +void Selector::Emit(llvm::Serializer& S) const { + S.EmitInt(getIdentifierInfoFlag()); + S.EmitPtr(reinterpret_cast(InfoPtr & ~ArgFlags)); +} + +Selector Selector::ReadVal(llvm::Deserializer& D) { + unsigned flag = D.ReadInt(); + + uintptr_t ptr; + D.ReadUIntPtr(ptr,false); // No backpatching. + + return Selector(ptr | flag); +} + +void SelectorTable::Emit(llvm::Serializer& S) const { + typedef llvm::FoldingSet::iterator iterator; + llvm::FoldingSet *SelTab; + SelTab = static_cast *>(Impl); + + S.EnterBlock(); + + S.EmitPtr(this); + + for (iterator I=SelTab->begin(), E=SelTab->end(); I != E; ++I) { + if (!S.isRegistered(&*I)) + continue; + + S.FlushRecord(); // Start a new record. + + S.EmitPtr(&*I); + S.EmitInt(I->getNumArgs()); + + for (MultiKeywordSelector::keyword_iterator KI = I->keyword_begin(), + KE = I->keyword_end(); KI != KE; ++KI) + S.EmitPtr(*KI); + } + + S.ExitBlock(); +} + +SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer& D) { + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + + SelectorTable* t = new SelectorTable(); + D.RegisterPtr(t); + + llvm::FoldingSet& SelTab = + *static_cast*>(t->Impl); + + while (!D.FinishedBlock(BLoc)) { + + llvm::SerializedPtrID PtrID = D.ReadPtrID(); + unsigned nKeys = D.ReadInt(); + + MultiKeywordSelector *SI = + (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + + nKeys*sizeof(IdentifierInfo *)); + + new (SI) MultiKeywordSelector(nKeys); + + D.RegisterPtr(PtrID,SI); + + IdentifierInfo **KeyInfo = reinterpret_cast(SI+1); + + for (unsigned i = 0; i != nKeys; ++i) + D.ReadPtr(KeyInfo[i],false); + + SelTab.GetOrInsertNode(SI); + } + + return t; +} diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp new file mode 100644 index 00000000000..f7fd91fbda5 --- /dev/null +++ b/clang/lib/Basic/LangOptions.cpp @@ -0,0 +1,58 @@ +//===--- LangOptions.cpp - Language feature info --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the methods for LangOptions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/LangOptions.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +void LangOptions::Emit(llvm::Serializer& S) const { + S.EmitBool((bool) Trigraphs); + S.EmitBool((bool) BCPLComment); + S.EmitBool((bool) DollarIdents); + S.EmitBool((bool) Digraphs); + S.EmitBool((bool) HexFloats); + S.EmitBool((bool) C99); + S.EmitBool((bool) Microsoft); + S.EmitBool((bool) CPlusPlus); + S.EmitBool((bool) CPlusPlus0x); + S.EmitBool((bool) NoExtensions); + S.EmitBool((bool) CXXOperatorNames); + S.EmitBool((bool) ObjC1); + S.EmitBool((bool) ObjC2); + S.EmitBool((bool) PascalStrings); + S.EmitBool((bool) Boolean); + S.EmitBool((bool) WritableStrings); + S.EmitBool((bool) LaxVectorConversions); +} + +void LangOptions::Read(llvm::Deserializer& D) { + Trigraphs = D.ReadBool() ? 1 : 0; + BCPLComment = D.ReadBool() ? 1 : 0; + DollarIdents = D.ReadBool() ? 1 : 0; + Digraphs = D.ReadBool() ? 1 : 0; + HexFloats = D.ReadBool() ? 1 : 0; + C99 = D.ReadBool() ? 1 : 0; + Microsoft = D.ReadBool() ? 1 : 0; + CPlusPlus = D.ReadBool() ? 1 : 0; + CPlusPlus0x = D.ReadBool() ? 1 : 0; + NoExtensions = D.ReadBool() ? 1 : 0; + CXXOperatorNames = D.ReadBool() ? 1 : 0; + ObjC1 = D.ReadBool() ? 1 : 0; + ObjC2 = D.ReadBool() ? 1 : 0; + PascalStrings = D.ReadBool() ? 1 : 0; + Boolean = D.ReadBool() ? 1 : 0; + WritableStrings = D.ReadBool() ? 1 : 0; + LaxVectorConversions = D.ReadBool() ? 1 : 0; +} diff --git a/clang/lib/Basic/Makefile b/clang/lib/Basic/Makefile new file mode 100644 index 00000000000..e95d6dbfa35 --- /dev/null +++ b/clang/lib/Basic/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/Basic/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Basic library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangBasic +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Basic/SourceLocation.cpp b/clang/lib/Basic/SourceLocation.cpp new file mode 100644 index 00000000000..eaf129f251e --- /dev/null +++ b/clang/lib/Basic/SourceLocation.cpp @@ -0,0 +1,79 @@ +//==--- SourceLocation.cpp - Compact identifier for Source Files -*- 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 serialization methods for the SourceLocation class. +// This file defines accessor methods for the FullSourceLoc class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +void SourceLocation::Emit(llvm::Serializer& S) const { + S.EmitInt(getRawEncoding()); +} + +SourceLocation SourceLocation::ReadVal(llvm::Deserializer& D) { + return SourceLocation::getFromRawEncoding(D.ReadInt()); +} + +void SourceRange::Emit(llvm::Serializer& S) const { + B.Emit(S); + E.Emit(S); +} + +SourceRange SourceRange::ReadVal(llvm::Deserializer& D) { + SourceLocation A = SourceLocation::ReadVal(D); + SourceLocation B = SourceLocation::ReadVal(D); + return SourceRange(A,B); +} + +FullSourceLoc FullSourceLoc::getLogicalLoc() { + assert (isValid()); + return FullSourceLoc(SrcMgr->getLogicalLoc(Loc),*SrcMgr); +} + +FullSourceLoc FullSourceLoc::getIncludeLoc() { + assert (isValid()); + return FullSourceLoc(SrcMgr->getIncludeLoc(Loc),*SrcMgr); +} + +unsigned FullSourceLoc::getLineNumber() { + assert (isValid()); + return SrcMgr->getLineNumber(Loc); +} + +unsigned FullSourceLoc::getColumnNumber() { + assert (isValid()); + return SrcMgr->getColumnNumber(Loc); +} + +const char* FullSourceLoc::getSourceName() const { + assert (isValid()); + return SrcMgr->getSourceName(Loc); +} + +const FileEntry* FullSourceLoc::getFileEntryForLoc() const { + assert (isValid()); + return SrcMgr->getFileEntryForLoc(Loc); +} + +const char * FullSourceLoc::getCharacterData() const { + assert (isValid()); + return SrcMgr->getCharacterData(Loc); +} + +const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { + assert (isValid()); + return SrcMgr->getBuffer(Loc.getFileID()); +} diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp new file mode 100644 index 00000000000..73ac2abe26f --- /dev/null +++ b/clang/lib/Basic/SourceManager.cpp @@ -0,0 +1,574 @@ +//===--- SourceManager.cpp - Track and cache source files -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceManager interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/Streams.h" +#include +#include +using namespace clang; +using namespace SrcMgr; +using llvm::MemoryBuffer; + +ContentCache::~ContentCache() { + delete Buffer; + delete [] SourceLineCache; +} + +// FIXME: REMOVE THESE +#include +#include +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#include +#else +#include +#endif +#include + +static const MemoryBuffer *ReadFileFast(const FileEntry *FileEnt) { +#if 0 + // FIXME: Reintroduce this and zap this function once the common llvm stuff + // is fast for the small case. + return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()), + FileEnt->getSize()); +#endif + + // If the file is larger than some threshold, use 'read', otherwise use mmap. + if (FileEnt->getSize() >= 4096*4) + return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()), + 0, FileEnt->getSize()); + + MemoryBuffer *SB = MemoryBuffer::getNewUninitMemBuffer(FileEnt->getSize(), + FileEnt->getName()); + char *BufPtr = const_cast(SB->getBufferStart()); + +#if defined(LLVM_ON_WIN32) + int FD = ::open(FileEnt->getName(), O_RDONLY|O_BINARY); +#else + int FD = ::open(FileEnt->getName(), O_RDONLY); +#endif + if (FD == -1) { + delete SB; + return 0; + } + + unsigned BytesLeft = FileEnt->getSize(); + while (BytesLeft) { + ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); + if (NumRead != -1) { + BytesLeft -= NumRead; + BufPtr += NumRead; + } else if (errno == EINTR) { + // try again + } else { + // error reading. + close(FD); + delete SB; + return 0; + } + } + close(FD); + + return SB; +} + + +/// getFileInfo - Create or return a cached FileInfo for the specified file. +/// +const ContentCache* SourceManager::getContentCache(const FileEntry *FileEnt) { + + assert(FileEnt && "Didn't specify a file entry to use?"); + // Do we already have information about this file? + std::set::iterator I = + FileInfos.lower_bound(ContentCache(FileEnt)); + + if (I != FileInfos.end() && I->Entry == FileEnt) + return &*I; + + // Nope, get information. + const MemoryBuffer *File = ReadFileFast(FileEnt); + if (File == 0) + return 0; + + ContentCache& Entry = const_cast(*FileInfos.insert(I,FileEnt)); + + Entry.Buffer = File; + Entry.SourceLineCache = 0; + Entry.NumLines = 0; + return &Entry; +} + + +/// createMemBufferContentCache - Create a new ContentCache for the specified +/// memory buffer. This does no caching. +const ContentCache* +SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { + // Add a new ContentCache to the MemBufferInfos list and return it. We + // must default construct the object first that the instance actually + // stored within MemBufferInfos actually owns the Buffer, and not any + // temporary we would use in the call to "push_back". + MemBufferInfos.push_back(ContentCache()); + ContentCache& Entry = const_cast(MemBufferInfos.back()); + Entry.Buffer = Buffer; + return &Entry; +} + + +/// createFileID - Create a new fileID for the specified ContentCache and +/// include position. This works regardless of whether the ContentCache +/// corresponds to a file or some other input source. +unsigned SourceManager::createFileID(const ContentCache *File, + SourceLocation IncludePos) { + // If FileEnt is really large (e.g. it's a large .i file), we may not be able + // to fit an arbitrary position in the file in the FilePos field. To handle + // this, we create one FileID for each chunk of the file that fits in a + // FilePos field. + unsigned FileSize = File->Buffer->getBufferSize(); + if (FileSize+1 < (1 << SourceLocation::FilePosBits)) { + FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File)); + assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && + "Ran out of file ID's!"); + return FileIDs.size(); + } + + // Create one FileID for each chunk of the file. + unsigned Result = FileIDs.size()+1; + + unsigned ChunkNo = 0; + while (1) { + FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File)); + + if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break; + FileSize -= (1 << SourceLocation::FilePosBits); + } + + assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && + "Ran out of file ID's!"); + return Result; +} + +/// getInstantiationLoc - Return a new SourceLocation that encodes the fact +/// that a token from physloc PhysLoc should actually be referenced from +/// InstantiationLoc. +SourceLocation SourceManager::getInstantiationLoc(SourceLocation PhysLoc, + SourceLocation InstantLoc) { + // The specified source location may be a mapped location, due to a macro + // instantiation or #line directive. Strip off this information to find out + // where the characters are actually located. + PhysLoc = getPhysicalLoc(PhysLoc); + + // Resolve InstantLoc down to a real logical location. + InstantLoc = getLogicalLoc(InstantLoc); + + + // If the last macro id is close to the currently requested location, try to + // reuse it. This implements a small cache. + for (int i = MacroIDs.size()-1, e = MacroIDs.size()-6; i >= 0 && i != e; --i){ + MacroIDInfo &LastOne = MacroIDs[i]; + + // The instanitation point and source physloc have to exactly match to reuse + // (for now). We could allow "nearby" instantiations in the future. + if (LastOne.getVirtualLoc() != InstantLoc || + LastOne.getPhysicalLoc().getFileID() != PhysLoc.getFileID()) + continue; + + // Check to see if the physloc of the token came from near enough to reuse. + int PhysDelta = PhysLoc.getRawFilePos() - + LastOne.getPhysicalLoc().getRawFilePos(); + if (SourceLocation::isValidMacroPhysOffs(PhysDelta)) + return SourceLocation::getMacroLoc(i, PhysDelta); + } + + + MacroIDs.push_back(MacroIDInfo::get(InstantLoc, PhysLoc)); + return SourceLocation::getMacroLoc(MacroIDs.size()-1, 0); +} + +/// getBufferData - Return a pointer to the start and end of the character +/// data for the specified FileID. +std::pair +SourceManager::getBufferData(unsigned FileID) const { + const llvm::MemoryBuffer *Buf = getBuffer(FileID); + return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); +} + + +/// getCharacterData - Return a pointer to the start of the specified location +/// in the appropriate MemoryBuffer. +const char *SourceManager::getCharacterData(SourceLocation SL) const { + // Note that this is a hot function in the getSpelling() path, which is + // heavily used by -E mode. + SL = getPhysicalLoc(SL); + + return getContentCache(SL.getFileID())->Buffer->getBufferStart() + + getFullFilePos(SL); +} + + +/// getColumnNumber - Return the column # for the specified file position. +/// this is significantly cheaper to compute than the line number. This returns +/// zero if the column number isn't known. +unsigned SourceManager::getColumnNumber(SourceLocation Loc) const { + unsigned FileID = Loc.getFileID(); + if (FileID == 0) return 0; + + unsigned FilePos = getFullFilePos(Loc); + const MemoryBuffer *Buffer = getBuffer(FileID); + const char *Buf = Buffer->getBufferStart(); + + unsigned LineStart = FilePos; + while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') + --LineStart; + return FilePos-LineStart+1; +} + +/// getSourceName - This method returns the name of the file or buffer that +/// the SourceLocation specifies. This can be modified with #line directives, +/// etc. +const char *SourceManager::getSourceName(SourceLocation Loc) const { + unsigned FileID = Loc.getFileID(); + if (FileID == 0) return ""; + return getContentCache(FileID)->Buffer->getBufferIdentifier(); +} + +static void ComputeLineNumbers(ContentCache* FI) DISABLE_INLINE; +static void ComputeLineNumbers(ContentCache* FI) { + const MemoryBuffer *Buffer = FI->Buffer; + + // Find the file offsets of all of the *physical* source lines. This does + // not look at trigraphs, escaped newlines, or anything else tricky. + std::vector LineOffsets; + + // Line #1 starts at char 0. + LineOffsets.push_back(0); + + const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); + const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); + unsigned Offs = 0; + while (1) { + // Skip over the contents of the line. + // TODO: Vectorize this? This is very performance sensitive for programs + // with lots of diagnostics and in -E mode. + const unsigned char *NextBuf = (const unsigned char *)Buf; + while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') + ++NextBuf; + Offs += NextBuf-Buf; + Buf = NextBuf; + + if (Buf[0] == '\n' || Buf[0] == '\r') { + // If this is \n\r or \r\n, skip both characters. + if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) + ++Offs, ++Buf; + ++Offs, ++Buf; + LineOffsets.push_back(Offs); + } else { + // Otherwise, this is a null. If end of file, exit. + if (Buf == End) break; + // Otherwise, skip the null. + ++Offs, ++Buf; + } + } + + // Copy the offsets into the FileInfo structure. + FI->NumLines = LineOffsets.size(); + FI->SourceLineCache = new unsigned[LineOffsets.size()]; + std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache); +} + +/// getLineNumber - Given a SourceLocation, return the physical line number +/// for the position indicated. This requires building and caching a table of +/// line offsets for the MemoryBuffer, so this is not cheap: use only when +/// about to emit a diagnostic. +unsigned SourceManager::getLineNumber(SourceLocation Loc) { + unsigned FileID = Loc.getFileID(); + if (FileID == 0) return 0; + + ContentCache* Content; + + if (LastLineNoFileIDQuery == FileID) + Content = LastLineNoContentCache; + else + Content = const_cast(getContentCache(FileID)); + + // If this is the first use of line information for this buffer, compute the + /// SourceLineCache for it on demand. + if (Content->SourceLineCache == 0) + ComputeLineNumbers(Content); + + // Okay, we know we have a line number table. Do a binary search to find the + // line number that this character position lands on. + unsigned *SourceLineCache = Content->SourceLineCache; + unsigned *SourceLineCacheStart = SourceLineCache; + unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines; + + unsigned QueriedFilePos = getFullFilePos(Loc)+1; + + // If the previous query was to the same file, we know both the file pos from + // that query and the line number returned. This allows us to narrow the + // search space from the entire file to something near the match. + if (LastLineNoFileIDQuery == FileID) { + if (QueriedFilePos >= LastLineNoFilePos) { + SourceLineCache = SourceLineCache+LastLineNoResult-1; + + // The query is likely to be nearby the previous one. Here we check to + // see if it is within 5, 10 or 20 lines. It can be far away in cases + // where big comment blocks and vertical whitespace eat up lines but + // contribute no tokens. + if (SourceLineCache+5 < SourceLineCacheEnd) { + if (SourceLineCache[5] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+5; + else if (SourceLineCache+10 < SourceLineCacheEnd) { + if (SourceLineCache[10] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+10; + else if (SourceLineCache+20 < SourceLineCacheEnd) { + if (SourceLineCache[20] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+20; + } + } + } + } else { + SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; + } + } + + // If the spread is large, do a "radix" test as our initial guess, based on + // the assumption that lines average to approximately the same length. + // NOTE: This is currently disabled, as it does not appear to be profitable in + // initial measurements. + if (0 && SourceLineCacheEnd-SourceLineCache > 20) { + unsigned FileLen = Content->SourceLineCache[Content->NumLines-1]; + + // Take a stab at guessing where it is. + unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen; + + // Check for -10 and +10 lines. + unsigned LowerBound = std::max(int(ApproxPos-10), 0); + unsigned UpperBound = std::min(ApproxPos+10, FileLen); + + // If the computed lower bound is less than the query location, move it in. + if (SourceLineCache < SourceLineCacheStart+LowerBound && + SourceLineCacheStart[LowerBound] < QueriedFilePos) + SourceLineCache = SourceLineCacheStart+LowerBound; + + // If the computed upper bound is greater than the query location, move it. + if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound && + SourceLineCacheStart[UpperBound] >= QueriedFilePos) + SourceLineCacheEnd = SourceLineCacheStart+UpperBound; + } + + unsigned *Pos + = std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos); + unsigned LineNo = Pos-SourceLineCacheStart; + + LastLineNoFileIDQuery = FileID; + LastLineNoContentCache = Content; + LastLineNoFilePos = QueriedFilePos; + LastLineNoResult = LineNo; + return LineNo; +} + +/// PrintStats - Print statistics to stderr. +/// +void SourceManager::PrintStats() const { + llvm::cerr << "\n*** Source Manager Stats:\n"; + llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size() + << " mem buffers mapped, " << FileIDs.size() + << " file ID's allocated.\n"; + llvm::cerr << " " << FileIDs.size() << " normal buffer FileID's, " + << MacroIDs.size() << " macro expansion FileID's.\n"; + + unsigned NumLineNumsComputed = 0; + unsigned NumFileBytesMapped = 0; + for (std::set::const_iterator I = + FileInfos.begin(), E = FileInfos.end(); I != E; ++I) { + NumLineNumsComputed += I->SourceLineCache != 0; + NumFileBytesMapped += I->Buffer->getBufferSize(); + } + + llvm::cerr << NumFileBytesMapped << " bytes of files mapped, " + << NumLineNumsComputed << " files with line #'s computed.\n"; +} + +//===----------------------------------------------------------------------===// +// Serialization. +//===----------------------------------------------------------------------===// + +void ContentCache::Emit(llvm::Serializer& S) const { + S.FlushRecord(); + S.EmitPtr(this); + + if (Entry) { + llvm::sys::Path Fname(Buffer->getBufferIdentifier()); + + if (Fname.isAbsolute()) + S.EmitCStr(Fname.c_str()); + else { + // Create an absolute path. + // FIXME: This will potentially contain ".." and "." in the path. + llvm::sys::Path path = llvm::sys::Path::GetCurrentDirectory(); + path.appendComponent(Fname.c_str()); + S.EmitCStr(path.c_str()); + } + } + else { + const char* p = Buffer->getBufferStart(); + const char* e = Buffer->getBufferEnd(); + + S.EmitInt(e-p); + + for ( ; p != e; ++p) + S.EmitInt(*p); + } + + S.FlushRecord(); +} + +void ContentCache::ReadToSourceManager(llvm::Deserializer& D, + SourceManager& SMgr, + FileManager* FMgr, + std::vector& Buf) { + if (FMgr) { + llvm::SerializedPtrID PtrID = D.ReadPtrID(); + D.ReadCStr(Buf,false); + + // Create/fetch the FileEntry. + const char* start = &Buf[0]; + const FileEntry* E = FMgr->getFile(start,start+Buf.size()); + + // FIXME: Ideally we want a lazy materialization of the ContentCache + // anyway, because we don't want to read in source files unless this + // is absolutely needed. + if (!E) + D.RegisterPtr(PtrID,NULL); + else + // Get the ContextCache object and register it with the deserializer. + D.RegisterPtr(PtrID,SMgr.getContentCache(E)); + } + else { + // Register the ContextCache object with the deserializer. + SMgr.MemBufferInfos.push_back(ContentCache()); + ContentCache& Entry = const_cast(SMgr.MemBufferInfos.back()); + D.RegisterPtr(&Entry); + + // Create the buffer. + unsigned Size = D.ReadInt(); + Entry.Buffer = MemoryBuffer::getNewUninitMemBuffer(Size); + + // Read the contents of the buffer. + char* p = const_cast(Entry.Buffer->getBufferStart()); + for (unsigned i = 0; i < Size ; ++i) + p[i] = D.ReadInt(); + } +} + +void FileIDInfo::Emit(llvm::Serializer& S) const { + S.Emit(IncludeLoc); + S.EmitInt(ChunkNo); + S.EmitPtr(Content); +} + +FileIDInfo FileIDInfo::ReadVal(llvm::Deserializer& D) { + FileIDInfo I; + I.IncludeLoc = SourceLocation::ReadVal(D); + I.ChunkNo = D.ReadInt(); + D.ReadPtr(I.Content,false); + return I; +} + +void MacroIDInfo::Emit(llvm::Serializer& S) const { + S.Emit(VirtualLoc); + S.Emit(PhysicalLoc); +} + +MacroIDInfo MacroIDInfo::ReadVal(llvm::Deserializer& D) { + MacroIDInfo I; + I.VirtualLoc = SourceLocation::ReadVal(D); + I.PhysicalLoc = SourceLocation::ReadVal(D); + return I; +} + +void SourceManager::Emit(llvm::Serializer& S) const { + S.EnterBlock(); + S.EmitPtr(this); + S.EmitInt(MainFileID); + + // Emit: FileInfos. Just emit the file name. + S.EnterBlock(); + + std::for_each(FileInfos.begin(),FileInfos.end(), + S.MakeEmitter()); + + S.ExitBlock(); + + // Emit: MemBufferInfos + S.EnterBlock(); + + std::for_each(MemBufferInfos.begin(), MemBufferInfos.end(), + S.MakeEmitter()); + + S.ExitBlock(); + + // Emit: FileIDs + S.EmitInt(FileIDs.size()); + std::for_each(FileIDs.begin(), FileIDs.end(), S.MakeEmitter()); + + // Emit: MacroIDs + S.EmitInt(MacroIDs.size()); + std::for_each(MacroIDs.begin(), MacroIDs.end(), S.MakeEmitter()); + + S.ExitBlock(); +} + +SourceManager* +SourceManager::CreateAndRegister(llvm::Deserializer& D, FileManager& FMgr){ + SourceManager *M = new SourceManager(); + D.RegisterPtr(M); + + // Read: the FileID of the main source file of the translation unit. + M->MainFileID = D.ReadInt(); + + std::vector Buf; + + { // Read: FileInfos. + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + while (!D.FinishedBlock(BLoc)) + ContentCache::ReadToSourceManager(D,*M,&FMgr,Buf); + } + + { // Read: MemBufferInfos. + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + while (!D.FinishedBlock(BLoc)) + ContentCache::ReadToSourceManager(D,*M,NULL,Buf); + } + + // Read: FileIDs. + unsigned Size = D.ReadInt(); + M->FileIDs.reserve(Size); + for (; Size > 0 ; --Size) + M->FileIDs.push_back(FileIDInfo::ReadVal(D)); + + // Read: MacroIDs. + Size = D.ReadInt(); + M->MacroIDs.reserve(Size); + for (; Size > 0 ; --Size) + M->MacroIDs.push_back(MacroIDInfo::ReadVal(D)); + + return M; +} diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp new file mode 100644 index 00000000000..0a561d75cb8 --- /dev/null +++ b/clang/lib/Basic/TargetInfo.cpp @@ -0,0 +1,210 @@ +//===--- TargetInfo.cpp - Information about Target machine ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TargetInfo and TargetInfoImpl interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/Builtins.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +// TargetInfo Constructor. +TargetInfo::TargetInfo(const std::string &T) : Triple(T) { + // Set defaults. These should be overridden by concrete targets as needed. + CharIsSigned = true; + WCharWidth = WCharAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEdouble; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; +} + +// Out of line virtual dtor for TargetInfo. +TargetInfo::~TargetInfo() {} + +//===----------------------------------------------------------------------===// + + +static void removeGCCRegisterPrefix(const char *&Name) { + if (Name[0] == '%' || Name[0] == '#') + Name++; +} + +/// isValidGCCRegisterName - Returns whether the passed in string +/// is a valid register name according to GCC. This is used by Sema for +/// inline asm statements. +bool TargetInfo::isValidGCCRegisterName(const char *Name) const { + const char * const *Names; + unsigned NumNames; + + // Get rid of any register prefix. + removeGCCRegisterPrefix(Name); + + + if (strcmp(Name, "memory") == 0 || + strcmp(Name, "cc") == 0) + return true; + + getGCCRegNames(Names, NumNames); + + // If we have a number it maps to an entry in the register name array. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) + return n >= 0 && (unsigned)n < NumNames; + } + + // Check register names. + for (unsigned i = 0; i < NumNames; i++) { + if (strcmp(Name, Names[i]) == 0) + return true; + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return true; + } + } + + return false; +} + +const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { + assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); + + removeGCCRegisterPrefix(Name); + + const char * const *Names; + unsigned NumNames; + + getGCCRegNames(Names, NumNames); + + // First, check if we have a number. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) { + assert(n >= 0 && (unsigned)n < NumNames && + "Out of bounds register number!"); + return Names[n]; + } + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return Aliases[i].Register; + } + } + + return Name; +} + +bool TargetInfo::validateOutputConstraint(const char *Name, + ConstraintInfo &info) const +{ + // An output constraint must start with '=' or '+' + if (*Name != '=' && *Name != '+') + return false; + + if (*Name == '+') + info = CI_ReadWrite; + else + info = CI_None; + + Name++; + while (*Name) { + switch (*Name) { + default: + if (!validateAsmConstraint(*Name, info)) { + // FIXME: This assert is in place temporarily + // so we can add more constraints as we hit it. + // Eventually, an unknown constraint should just be treated as 'g'. + assert(0 && "Unknown output constraint type!"); + } + case '&': // early clobber. + break; + case 'r': // general register. + info = (ConstraintInfo)(info|CI_AllowsRegister); + break; + case 'm': // memory operand. + info = (ConstraintInfo)(info|CI_AllowsMemory); + break; + case 'g': // general register, memory operand or immediate integer. + info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister); + break; + } + + Name++; + } + + return true; +} + +bool TargetInfo::validateInputConstraint(const char *Name, + unsigned NumOutputs, + ConstraintInfo &info) const { + while (*Name) { + switch (*Name) { + default: + // Check if we have a matching constraint + if (*Name >= '0' && *Name <= '9') { + unsigned i = *Name - '0'; + + // Check if matching constraint is out of bounds. + if (i >= NumOutputs) + return false; + } else if (!validateAsmConstraint(*Name, info)) { + // FIXME: This assert is in place temporarily + // so we can add more constraints as we hit it. + // Eventually, an unknown constraint should just be treated as 'g'. + assert(0 && "Unknown input constraint type!"); + } + case '%': // commutative + // FIXME: Fail if % is used with the last operand. + break; + case 'i': // immediate integer. + case 'I': + case 'n': // immediate integer with a known value. + break; + case 'r': // general register. + info = (ConstraintInfo)(info|CI_AllowsRegister); + break; + case 'm': // memory operand. + info = (ConstraintInfo)(info|CI_AllowsMemory); + break; + case 'g': // general register, memory operand or immediate integer. + info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister); + break; + } + + Name++; + } + + return true; +} diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp new file mode 100644 index 00000000000..e8238daeae3 --- /dev/null +++ b/clang/lib/Basic/Targets.cpp @@ -0,0 +1,757 @@ +//===--- Targets.cpp - Implement -arch option and targets -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements construction of a TargetInfo object from a +// target triple. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Builtins.h" +#include "clang/AST/TargetBuiltins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Common code shared among targets. +//===----------------------------------------------------------------------===// + +static void Define(std::vector &Buf, const char *Macro, + const char *Val = "1") { + const char *Def = "#define "; + Buf.insert(Buf.end(), Def, Def+strlen(Def)); + Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); + Buf.push_back(' '); + Buf.insert(Buf.end(), Val, Val+strlen(Val)); + Buf.push_back('\n'); +} + + +namespace { +class DarwinTargetInfo : public TargetInfo { +public: + DarwinTargetInfo(const std::string& triple) : TargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defs) const { +// FIXME: we need a real target configuration system. For now, only define +// __APPLE__ if the host has it. +#ifdef __APPLE__ + Define(Defs, "__APPLE__"); + Define(Defs, "__MACH__"); +#endif + + if (1) {// -fobjc-gc controls this. + Define(Defs, "__weak", ""); + Define(Defs, "__strong", ""); + } else { + Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); + Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); + Define(Defs, "__OBJC_GC__"); + } + + // darwin_constant_cfstrings controls this. + Define(Defs, "__CONSTANT_CFSTRINGS__"); + + if (0) // darwin_pascal_strings + Define(Defs, "__PASCAL_STRINGS__"); + } + +}; + + +class SolarisTargetInfo : public TargetInfo { +public: + SolarisTargetInfo(const std::string& triple) : TargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defs) const { +// FIXME: we need a real target configuration system. For now, only define +// __SUN__ if the host has it. +#ifdef __SUN__ + Define(Defs, "__SUN__"); + Define(Defs, "__SOLARIS__"); +#endif + + if (1) {// -fobjc-gc controls this. + Define(Defs, "__weak", ""); + Define(Defs, "__strong", ""); + } else { + Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); + Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); + Define(Defs, "__OBJC_GC__"); + } + } + +}; +} // end anonymous namespace. + + +/// getPowerPCDefines - Return a set of the PowerPC-specific #defines that are +/// not tied to a specific subtarget. +static void getPowerPCDefines(std::vector &Defs, bool is64Bit) { + // Target identification. + Define(Defs, "__ppc__"); + Define(Defs, "_ARCH_PPC"); + Define(Defs, "__POWERPC__"); + if (is64Bit) { + Define(Defs, "_ARCH_PPC64"); + Define(Defs, "_LP64"); + Define(Defs, "__LP64__"); + Define(Defs, "__ppc64__"); + } else { + Define(Defs, "__ppc__"); + } + + // Target properties. + Define(Defs, "_BIG_ENDIAN"); + Define(Defs, "__BIG_ENDIAN__"); + + if (is64Bit) { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807L"); + Define(Defs, "__INTMAX_TYPE__", "long int"); + Define(Defs, "__LONG_MAX__", "9223372036854775807L"); + Define(Defs, "__PTRDIFF_TYPE__", "long int"); + Define(Defs, "__UINTMAX_TYPE__", "long unsigned int"); + } else { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL"); + Define(Defs, "__INTMAX_TYPE__", "long long int"); + Define(Defs, "__LONG_MAX__", "2147483647L"); + Define(Defs, "__PTRDIFF_TYPE__", "int"); + Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int"); + } + Define(Defs, "__INT_MAX__", "2147483647"); + Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL"); + Define(Defs, "__CHAR_BIT__", "8"); + Define(Defs, "__SCHAR_MAX__", "127"); + Define(Defs, "__SHRT_MAX__", "32767"); + Define(Defs, "__SIZE_TYPE__", "long unsigned int"); + + // Subtarget options. + Define(Defs, "__USER_LABEL_PREFIX__", "_"); + Define(Defs, "__NATURAL_ALIGNMENT__"); + Define(Defs, "__REGISTER_PREFIX__", ""); + + Define(Defs, "__WCHAR_MAX__", "2147483647"); + Define(Defs, "__WCHAR_TYPE__", "int"); + Define(Defs, "__WINT_TYPE__", "int"); + + // Float macros. + Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F"); + Define(Defs, "__FLT_DIG__", "6"); + Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F"); + Define(Defs, "__FLT_EVAL_METHOD__", "0"); + Define(Defs, "__FLT_HAS_INFINITY__"); + Define(Defs, "__FLT_HAS_QUIET_NAN__"); + Define(Defs, "__FLT_MANT_DIG__", "24"); + Define(Defs, "__FLT_MAX_10_EXP__", "38"); + Define(Defs, "__FLT_MAX_EXP__", "128"); + Define(Defs, "__FLT_MAX__", "3.40282347e+38F"); + Define(Defs, "__FLT_MIN_10_EXP__", "(-37)"); + Define(Defs, "__FLT_MIN_EXP__", "(-125)"); + Define(Defs, "__FLT_MIN__", "1.17549435e-38F"); + Define(Defs, "__FLT_RADIX__", "2"); + + // double macros. + Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324"); + Define(Defs, "__DBL_DIG__", "15"); + Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16"); + Define(Defs, "__DBL_HAS_INFINITY__"); + Define(Defs, "__DBL_HAS_QUIET_NAN__"); + Define(Defs, "__DBL_MANT_DIG__", "53"); + Define(Defs, "__DBL_MAX_10_EXP__", "308"); + Define(Defs, "__DBL_MAX_EXP__", "1024"); + Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308"); + Define(Defs, "__DBL_MIN_10_EXP__", "(-307)"); + Define(Defs, "__DBL_MIN_EXP__", "(-1021)"); + Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308"); + Define(Defs, "__DECIMAL_DIG__", "33"); + + // 128-bit long double macros. + Define(Defs, "__LDBL_DENORM_MIN__", + "4.94065645841246544176568792868221e-324L"); + Define(Defs, "__LDBL_DIG__", "31"); + Define(Defs, "__LDBL_EPSILON__", + "4.94065645841246544176568792868221e-324L"); + Define(Defs, "__LDBL_HAS_INFINITY__"); + Define(Defs, "__LDBL_HAS_QUIET_NAN__"); + Define(Defs, "__LDBL_MANT_DIG__", "106"); + Define(Defs, "__LDBL_MAX_10_EXP__", "308"); + Define(Defs, "__LDBL_MAX_EXP__", "1024"); + Define(Defs, "__LDBL_MAX__", + "1.79769313486231580793728971405301e+308L"); + Define(Defs, "__LDBL_MIN_10_EXP__", "(-291)"); + Define(Defs, "__LDBL_MIN_EXP__", "(-968)"); + Define(Defs, "__LDBL_MIN__", + "2.00416836000897277799610805135016e-292L"); + Define(Defs, "__LONG_DOUBLE_128__"); +} + +/// getX86Defines - Return a set of the X86-specific #defines that are +/// not tied to a specific subtarget. +static void getX86Defines(std::vector &Defs, bool is64Bit) { + // Target identification. + if (is64Bit) { + Define(Defs, "_LP64"); + Define(Defs, "__LP64__"); + Define(Defs, "__amd64__"); + Define(Defs, "__amd64"); + Define(Defs, "__x86_64"); + Define(Defs, "__x86_64__"); + } else { + Define(Defs, "__i386__"); + Define(Defs, "__i386"); + Define(Defs, "i386"); + } + + // Target properties. + Define(Defs, "__LITTLE_ENDIAN__"); + + if (is64Bit) { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807L"); + Define(Defs, "__INTMAX_TYPE__", "long int"); + Define(Defs, "__LONG_MAX__", "9223372036854775807L"); + Define(Defs, "__PTRDIFF_TYPE__", "long int"); + Define(Defs, "__UINTMAX_TYPE__", "long unsigned int"); + Define(Defs, "__SIZE_TYPE__", "long unsigned int"); + } else { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL"); + Define(Defs, "__INTMAX_TYPE__", "long long int"); + Define(Defs, "__LONG_MAX__", "2147483647L"); + Define(Defs, "__PTRDIFF_TYPE__", "int"); + Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int"); + Define(Defs, "__SIZE_TYPE__", "unsigned int"); + } + Define(Defs, "__CHAR_BIT__", "8"); + Define(Defs, "__INT_MAX__", "2147483647"); + Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL"); + Define(Defs, "__SCHAR_MAX__", "127"); + Define(Defs, "__SHRT_MAX__", "32767"); + + // Subtarget options. + Define(Defs, "__nocona"); + Define(Defs, "__nocona__"); + Define(Defs, "__tune_nocona__"); + Define(Defs, "__SSE2_MATH__"); + Define(Defs, "__SSE2__"); + Define(Defs, "__SSE_MATH__"); + Define(Defs, "__SSE__"); + Define(Defs, "__MMX__"); + Define(Defs, "__REGISTER_PREFIX__", ""); + + Define(Defs, "__WCHAR_MAX__", "2147483647"); + Define(Defs, "__WCHAR_TYPE__", "int"); + Define(Defs, "__WINT_TYPE__", "int"); + + // Float macros. + Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F"); + Define(Defs, "__FLT_DIG__", "6"); + Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F"); + Define(Defs, "__FLT_EVAL_METHOD__", "0"); + Define(Defs, "__FLT_HAS_INFINITY__"); + Define(Defs, "__FLT_HAS_QUIET_NAN__"); + Define(Defs, "__FLT_MANT_DIG__", "24"); + Define(Defs, "__FLT_MAX_10_EXP__", "38"); + Define(Defs, "__FLT_MAX_EXP__", "128"); + Define(Defs, "__FLT_MAX__", "3.40282347e+38F"); + Define(Defs, "__FLT_MIN_10_EXP__", "(-37)"); + Define(Defs, "__FLT_MIN_EXP__", "(-125)"); + Define(Defs, "__FLT_MIN__", "1.17549435e-38F"); + Define(Defs, "__FLT_RADIX__", "2"); + + // Double macros. + Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324"); + Define(Defs, "__DBL_DIG__", "15"); + Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16"); + Define(Defs, "__DBL_HAS_INFINITY__"); + Define(Defs, "__DBL_HAS_QUIET_NAN__"); + Define(Defs, "__DBL_MANT_DIG__", "53"); + Define(Defs, "__DBL_MAX_10_EXP__", "308"); + Define(Defs, "__DBL_MAX_EXP__", "1024"); + Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308"); + Define(Defs, "__DBL_MIN_10_EXP__", "(-307)"); + Define(Defs, "__DBL_MIN_EXP__", "(-1021)"); + Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308"); + Define(Defs, "__DECIMAL_DIG__", "21"); + + // 80-bit Long double macros. + Define(Defs, "__LDBL_DENORM_MIN__", "3.64519953188247460253e-4951L"); + Define(Defs, "__LDBL_DIG__", "18"); + Define(Defs, "__LDBL_EPSILON__", "1.08420217248550443401e-19L"); + Define(Defs, "__LDBL_HAS_INFINITY__"); + Define(Defs, "__LDBL_HAS_QUIET_NAN__"); + Define(Defs, "__LDBL_MANT_DIG__", "64"); + Define(Defs, "__LDBL_MAX_10_EXP__", "4932"); + Define(Defs, "__LDBL_MAX_EXP__", "16384"); + Define(Defs, "__LDBL_MAX__", "1.18973149535723176502e+4932L"); + Define(Defs, "__LDBL_MIN_10_EXP__", "(-4931)"); + Define(Defs, "__LDBL_MIN_EXP__", "(-16381)"); + Define(Defs, "__LDBL_MIN__", "3.36210314311209350626e-4932L"); +} + +static const char* getI386VAListDeclaration() { + return "typedef char* __builtin_va_list;"; +} + +static const char* getX86_64VAListDeclaration() { + return + "typedef struct __va_list_tag {" + " unsigned gp_offset;" + " unsigned fp_offset;" + " void* overflow_arg_area;" + " void* reg_save_area;" + "} __builtin_va_list[1];"; +} + +static const char* getPPCVAListDeclaration() { + return + "typedef struct __va_list_tag {" + " unsigned char gpr;" + " unsigned char fpr;" + " unsigned short reserved;" + " void* overflow_arg_area;" + " void* reg_save_area;" + "} __builtin_va_list[1];"; +} + + +/// PPC builtin info. +namespace clang { +namespace PPC { + + static const Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/PPCBuiltins.def" + }; + + static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) { + Records = BuiltinInfo; + NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + static const char * const GCCRegNames[] = { + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "mq", "lr", "ctr", "ap", + "0", "1", "2", "3", "4", "5", "6", "7", + "xer", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "vrsave", "vscr", + "spe_acc", "spefscr", + "sfp" + }; + + static void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + // While some of these aliases do map to different registers + // they still share the same register name. + { { "cc", "cr0", "fr0", "r0", "v0"}, "0" }, + { { "cr1", "fr1", "r1", "sp", "v1"}, "1" }, + { { "cr2", "fr2", "r2", "toc", "v2"}, "2" }, + { { "cr3", "fr3", "r3", "v3"}, "3" }, + { { "cr4", "fr4", "r4", "v4"}, "4" }, + { { "cr5", "fr5", "r5", "v5"}, "5" }, + { { "cr6", "fr6", "r6", "v6"}, "6" }, + { { "cr7", "fr7", "r7", "v7"}, "7" }, + { { "fr8", "r8", "v8"}, "8" }, + { { "fr9", "r9", "v9"}, "9" }, + { { "fr10", "r10", "v10"}, "10" }, + { { "fr11", "r11", "v11"}, "11" }, + { { "fr12", "r12", "v12"}, "12" }, + { { "fr13", "r13", "v13"}, "13" }, + { { "fr14", "r14", "v14"}, "14" }, + { { "fr15", "r15", "v15"}, "15" }, + { { "fr16", "r16", "v16"}, "16" }, + { { "fr17", "r17", "v17"}, "17" }, + { { "fr18", "r18", "v18"}, "18" }, + { { "fr19", "r19", "v19"}, "19" }, + { { "fr20", "r20", "v20"}, "20" }, + { { "fr21", "r21", "v21"}, "21" }, + { { "fr22", "r22", "v22"}, "22" }, + { { "fr23", "r23", "v23"}, "23" }, + { { "fr24", "r24", "v24"}, "24" }, + { { "fr25", "r25", "v25"}, "25" }, + { { "fr26", "r26", "v26"}, "26" }, + { { "fr27", "r27", "v27"}, "27" }, + { { "fr28", "r28", "v28"}, "28" }, + { { "fr29", "r29", "v29"}, "29" }, + { { "fr30", "r30", "v30"}, "30" }, + { { "fr31", "r31", "v31"}, "31" }, + }; + + static void getGCCRegAliases(const TargetInfo::GCCRegAlias *&Aliases, + unsigned &NumAliases) { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } + + static bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) { + switch (c) { + default: return false; + case 'O': // Zero + return true; + case 'b': // Base register + case 'f': // Floating point register + info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister); + return true; + } + } + + const char *getClobbers() { + return 0; + } + + const char *getTargetPrefix() { + return "ppc"; + } + +} // End namespace PPC + +/// X86 builtin info. +namespace X86 { + static const Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/X86Builtins.def" + }; + + static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) { + Records = BuiltinInfo; + NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + static const char *GCCRegNames[] = { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", + "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "argp", "flags", "fspr", "dirflag", "frame", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" + }; + + static void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + { { "al", "ah", "eax", "rax" }, "ax" }, + { { "bl", "bh", "ebx", "rbx" }, "bx" }, + { { "cl", "ch", "ecx", "rcx" }, "cx" }, + { { "dl", "dh", "edx", "rdx" }, "dx" }, + { { "esi", "rsi" }, "si" }, + { { "esp", "rsp" }, "sp" }, + { { "ebp", "rbp" }, "bp" }, + }; + + static void getGCCRegAliases(const TargetInfo::GCCRegAlias *&Aliases, + unsigned &NumAliases) { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } + + static bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) { + switch (c) { + default: return false; + case 'a': // eax. + case 'b': // ebx. + case 'c': // ecx. + case 'd': // edx. + case 'S': // esi. + case 'D': // edi. + case 'A': // edx:eax. + case 't': // top of floating point stack. + case 'u': // second from top of floating point stack. + case 'q': // a, b, c, d registers or any integer register in 64-bit. + case 'Z': // 32-bit integer constant for use with zero-extending x86_64 + // instructions. + case 'N': // unsigned 8-bit integer constant for use with in and out + // instructions. + info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister); + return true; + } + } + + static std::string convertConstraint(const char Constraint) { + switch (Constraint) { + case 'a': return std::string("{ax}"); + case 'b': return std::string("{bx}"); + case 'c': return std::string("{cx}"); + case 'd': return std::string("{dx}"); + case 'S': return std::string("{si}"); + case 'D': return std::string("{di}"); + case 't': // top of floating point stack. + return std::string("{st}"); + case 'u': // second from top of floating point stack. + return std::string("{st(1)}"); // second from top of floating point stack. + default: + return std::string(1, Constraint); + } + } + + const char *getClobbers() { + return "~{dirflag},~{fpsr},~{flags}"; + } + + const char *getTargetPrefix() { + return "x86"; + } + +} // End namespace X86 +} // end namespace clang. + +//===----------------------------------------------------------------------===// +// Specific target implementations. +//===----------------------------------------------------------------------===// + + +namespace { +class DarwinPPCTargetInfo : public DarwinTargetInfo { +public: + DarwinPPCTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getPowerPCDefines(Defines, false); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + PPC::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getPPCVAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return PPC::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + PPC::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + PPC::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return PPC::validateAsmConstraint(c, info); + } + virtual const char *getClobbers() const { + return PPC::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinPPC64TargetInfo : public DarwinTargetInfo { +public: + DarwinPPC64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getPowerPCDefines(Defines, true); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + PPC::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getPPCVAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return PPC::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + PPC::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + PPC::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return PPC::validateAsmConstraint(c, info); + } + virtual const char *getClobbers() const { + return PPC::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinI386TargetInfo : public DarwinTargetInfo { +public: + DarwinI386TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getX86Defines(Defines, false); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + X86::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getI386VAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return X86::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + X86::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + X86::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return X86::validateAsmConstraint(c, info); + } + + virtual std::string convertConstraint(const char Constraint) const { + return X86::convertConstraint(Constraint); + } + + virtual const char *getClobbers() const { + return X86::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinX86_64TargetInfo : public DarwinTargetInfo { +public: + DarwinX86_64TargetInfo(const std::string& triple) :DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getX86Defines(Defines, true); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + X86::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getX86_64VAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return X86::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + X86::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + X86::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return X86::validateAsmConstraint(c, info); + } + virtual std::string convertConstraint(const char Constraint) const { + return X86::convertConstraint(Constraint); + } + virtual const char *getClobbers() const { + return X86::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class SolarisSparcV8TargetInfo : public SolarisTargetInfo { +public: + SolarisSparcV8TargetInfo(const std::string& triple) : SolarisTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector &Defines) const { + SolarisTargetInfo::getTargetDefines(Defines); +// getSparcDefines(Defines, false); + Define(Defines, "__sparc"); + Define(Defines, "__sparcv8"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + PPC::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getPPCVAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return PPC::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + PPC::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + PPC::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return PPC::validateAsmConstraint(c, info); + } + virtual const char *getClobbers() const { + return PPC::getClobbers(); + } +}; + +} // end anonymous namespace. + + +//===----------------------------------------------------------------------===// +// Driver code +//===----------------------------------------------------------------------===// + +static inline bool IsX86(const std::string& TT) { + return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' && + TT[4] == '-' && TT[1] - '3' < 6); +} + +/// CreateTargetInfo - Return the target info object for the specified target +/// triple. +TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { + if (T.find("ppc-") == 0 || T.find("powerpc-") == 0) + return new DarwinPPCTargetInfo(T); + + if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) + return new DarwinPPC64TargetInfo(T); + + if (T.find("sparc-") == 0) + return new SolarisSparcV8TargetInfo(T); // ugly hack + + if (T.find("x86_64-") == 0) + return new DarwinX86_64TargetInfo(T); + + if (IsX86(T)) + return new DarwinI386TargetInfo(T); + + return NULL; +} + diff --git a/clang/lib/Basic/TokenKinds.cpp b/clang/lib/Basic/TokenKinds.cpp new file mode 100644 index 00000000000..bde8a5598b4 --- /dev/null +++ b/clang/lib/Basic/TokenKinds.cpp @@ -0,0 +1,29 @@ +//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TokenKind enum and support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TokenKinds.h" + +#include +using namespace clang; + +static const char * const TokNames[] = { +#define TOK(X) #X, +#define KEYWORD(X,Y) #X, +#include "clang/Basic/TokenKinds.def" + 0 +}; + +const char *tok::getTokenName(enum TokenKind Kind) { + assert(Kind < tok::NUM_TOKENS); + return TokNames[Kind]; +} diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp new file mode 100644 index 00000000000..83c5e60475c --- /dev/null +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -0,0 +1,486 @@ +//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Builtin calls as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Builtins.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TargetBuiltins.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +using namespace clang; +using namespace CodeGen; +using namespace llvm; + +RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + switch (BuiltinID) { + default: { + if (getContext().BuiltinInfo.isLibFunction(BuiltinID)) + return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), + E->getCallee()->getType(), E->arg_begin(), + E->getNumArgs()); + + // See if we have a target specific intrinsic. + Intrinsic::ID IntrinsicID; + const char *TargetPrefix = Target.getTargetPrefix(); + const char *BuiltinName = getContext().BuiltinInfo.GetName(BuiltinID); +#define GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN +#include "llvm/Intrinsics.gen" +#undef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN + + if (IntrinsicID != Intrinsic::not_intrinsic) { + SmallVector Args; + + Function *F = CGM.getIntrinsic(IntrinsicID); + const llvm::FunctionType *FTy = F->getFunctionType(); + + for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { + Value *ArgValue = EmitScalarExpr(E->getArg(i)); + + // If the intrinsic arg type is different from the builtin arg type + // we need to do a bit cast. + const llvm::Type *PTy = FTy->getParamType(i); + if (PTy != ArgValue->getType()) { + assert(PTy->canLosslesslyBitCastTo(FTy->getParamType(i)) && + "Must be able to losslessly bit cast to param"); + ArgValue = Builder.CreateBitCast(ArgValue, PTy); + } + + Args.push_back(ArgValue); + } + + Value *V = Builder.CreateCall(F, &Args[0], &Args[0] + Args.size()); + QualType BuiltinRetType = E->getType(); + + const llvm::Type *RetTy = llvm::Type::VoidTy; + if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType); + + if (RetTy != V->getType()) { + assert(V->getType()->canLosslesslyBitCastTo(RetTy) && + "Must be able to losslessly bit cast result type"); + V = Builder.CreateBitCast(V, RetTy); + } + + return RValue::get(V); + } + + // See if we have a target specific builtin that needs to be lowered. + Value *V = 0; + + if (strcmp(TargetPrefix, "x86") == 0) + V = EmitX86BuiltinExpr(BuiltinID, E); + else if (strcmp(TargetPrefix, "ppc") == 0) + V = EmitPPCBuiltinExpr(BuiltinID, E); + + if (V) + return RValue::get(V); + + WarnUnsupported(E, "builtin function"); + + // Unknown builtin, for now just dump it out and return undef. + if (hasAggregateLLVMType(E->getType())) + return RValue::getAggregate(CreateTempAlloca(ConvertType(E->getType()))); + return RValue::get(UndefValue::get(ConvertType(E->getType()))); + } + case Builtin::BI__builtin___CFStringMakeConstantString: { + const Expr *Arg = E->getArg(0); + + while (1) { + if (const ParenExpr *PE = dyn_cast(Arg)) + Arg = PE->getSubExpr(); + else if (const ImplicitCastExpr *CE = dyn_cast(Arg)) + Arg = CE->getSubExpr(); + else + break; + } + + const StringLiteral *Literal = cast(Arg); + std::string S(Literal->getStrData(), Literal->getByteLength()); + + return RValue::get(CGM.GetAddrOfConstantCFString(S)); + } + case Builtin::BI__builtin_va_start: + case Builtin::BI__builtin_va_end: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + const llvm::Type *DestType = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + if (ArgValue->getType() != DestType) + ArgValue = Builder.CreateBitCast(ArgValue, DestType, + ArgValue->getNameStart()); + + Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_start) ? + Intrinsic::vastart : Intrinsic::vaend; + return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue)); + } + case Builtin::BI__builtin_va_copy: { + // FIXME: This does not yet handle architectures where va_list is a struct. + Value *DstPtr = EmitScalarExpr(E->getArg(0)); + Value *SrcValue = EmitScalarExpr(E->getArg(1)); + + Value *SrcPtr = CreateTempAlloca(SrcValue->getType(), "dst_ptr"); + + // FIXME: Volatile + Builder.CreateStore(SrcValue, SrcPtr, false); + + const llvm::Type *Type = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + + DstPtr = Builder.CreateBitCast(DstPtr, Type); + SrcPtr = Builder.CreateBitCast(SrcPtr, Type); + Value *Args[] = { DstPtr, SrcPtr }; + return RValue::get(Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy), + &Args[0], &Args[2])); + } + case Builtin::BI__builtin_classify_type: { + APSInt Result(32); + if (!E->isBuiltinClassifyType(Result)) + assert(0 && "Expr not __builtin_classify_type!"); + return RValue::get(ConstantInt::get(Result)); + } + case Builtin::BI__builtin_constant_p: { + APSInt Result(32); + // FIXME: Analyze the parameter and check if it is a constant. + Result = 0; + return RValue::get(ConstantInt::get(Result)); + } + case Builtin::BI__builtin_abs: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + + llvm::BinaryOperator *NegOp = + Builder.CreateNeg(ArgValue, (ArgValue->getName() + "neg").c_str()); + Value *CmpResult = + Builder.CreateICmpSGE(ArgValue, NegOp->getOperand(0), "abscond"); + Value *Result = + Builder.CreateSelect(CmpResult, ArgValue, NegOp, "abs"); + + return RValue::get(Result); + } + case Builtin::BI__builtin_ctz: + case Builtin::BI__builtin_ctzl: + case Builtin::BI__builtin_ctzll: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + + const llvm::Type *ArgType = ArgValue->getType(); + Value *F = CGM.getIntrinsic(Intrinsic::cttz, &ArgType, 1); + + const llvm::Type *ResultType = ConvertType(E->getType()); + Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); + if (Result->getType() != ResultType) + Result = Builder.CreateIntCast(Result, ResultType, "cast"); + return RValue::get(Result); + } + case Builtin::BI__builtin_expect: + return RValue::get(EmitScalarExpr(E->getArg(0))); + case Builtin::BI__builtin_bswap32: + case Builtin::BI__builtin_bswap64: { + Value *ArgValue = EmitScalarExpr(E->getArg(0)); + const llvm::Type *ArgType = ArgValue->getType(); + Value *F = CGM.getIntrinsic(Intrinsic::bswap, &ArgType, 1); + return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); + } + case Builtin::BI__builtin_inff: { + APFloat f(APFloat::IEEEsingle, APFloat::fcInfinity, false); + return RValue::get(ConstantFP::get(llvm::Type::FloatTy, f)); + } + case Builtin::BI__builtin_huge_val: + case Builtin::BI__builtin_inf: + // FIXME: mapping long double onto double. + case Builtin::BI__builtin_infl: { + APFloat f(APFloat::IEEEdouble, APFloat::fcInfinity, false); + return RValue::get(ConstantFP::get(llvm::Type::DoubleTy, f)); + } + case Builtin::BI__builtin_isgreater: + case Builtin::BI__builtin_isgreaterequal: + case Builtin::BI__builtin_isless: + case Builtin::BI__builtin_islessequal: + case Builtin::BI__builtin_islessgreater: + case Builtin::BI__builtin_isunordered: { + // Ordered comparisons: we know the arguments to these are matching scalar + // floating point values. + Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *RHS = EmitScalarExpr(E->getArg(1)); + + switch (BuiltinID) { + default: assert(0 && "Unknown ordered comparison"); + case Builtin::BI__builtin_isgreater: + LHS = Builder.CreateFCmpOGT(LHS, RHS, "cmp"); + break; + case Builtin::BI__builtin_isgreaterequal: + LHS = Builder.CreateFCmpOGE(LHS, RHS, "cmp"); + break; + case Builtin::BI__builtin_isless: + LHS = Builder.CreateFCmpOLT(LHS, RHS, "cmp"); + break; + case Builtin::BI__builtin_islessequal: + LHS = Builder.CreateFCmpOLE(LHS, RHS, "cmp"); + break; + case Builtin::BI__builtin_islessgreater: + LHS = Builder.CreateFCmpONE(LHS, RHS, "cmp"); + break; + case Builtin::BI__builtin_isunordered: + LHS = Builder.CreateFCmpUNO(LHS, RHS, "cmp"); + break; + } + // ZExt bool to int type. + return RValue::get(Builder.CreateZExt(LHS, ConvertType(E->getType()), + "tmp")); + } + case Builtin::BI__builtin_alloca: + return RValue::get(Builder.CreateAlloca(llvm::Type::Int8Ty, + EmitScalarExpr(E->getArg(0)), + "tmp")); + } + return RValue::get(0); +} + +Value *CodeGenFunction::EmitX86BuiltinExpr(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))); + + switch (BuiltinID) { + default: return 0; + case X86::BI__builtin_ia32_mulps: + return Builder.CreateMul(Ops[0], Ops[1], "mulps"); + case X86::BI__builtin_ia32_pand: + return Builder.CreateAnd(Ops[0], Ops[1], "pand"); + case X86::BI__builtin_ia32_por: + return Builder.CreateAnd(Ops[0], Ops[1], "por"); + case X86::BI__builtin_ia32_pxor: + return Builder.CreateAnd(Ops[0], Ops[1], "pxor"); + case X86::BI__builtin_ia32_pandn: { + Ops[0] = Builder.CreateNot(Ops[0], "tmp"); + return Builder.CreateAnd(Ops[0], Ops[1], "pandn"); + } + case X86::BI__builtin_ia32_paddb: + case X86::BI__builtin_ia32_paddd: + case X86::BI__builtin_ia32_paddq: + case X86::BI__builtin_ia32_paddw: + case X86::BI__builtin_ia32_addps: + return Builder.CreateAdd(Ops[0], Ops[1], "add"); + case X86::BI__builtin_ia32_psubb: + case X86::BI__builtin_ia32_psubd: + case X86::BI__builtin_ia32_psubq: + case X86::BI__builtin_ia32_psubw: + case X86::BI__builtin_ia32_subps: + return Builder.CreateSub(Ops[0], Ops[1], "sub"); + case X86::BI__builtin_ia32_divps: + return Builder.CreateFDiv(Ops[0], Ops[1], "divps"); + case X86::BI__builtin_ia32_pmullw: + return Builder.CreateMul(Ops[0], Ops[1], "pmul"); + case X86::BI__builtin_ia32_punpckhbw: + return EmitShuffleVector(Ops[0], Ops[1], 4, 12, 5, 13, 6, 14, 7, 15, + "punpckhbw"); + case X86::BI__builtin_ia32_punpckhwd: + return EmitShuffleVector(Ops[0], Ops[1], 2, 6, 3, 7, "punpckhwd"); + case X86::BI__builtin_ia32_punpckhdq: + return EmitShuffleVector(Ops[0], Ops[1], 1, 3, "punpckhdq"); + case X86::BI__builtin_ia32_punpcklbw: + return EmitShuffleVector(Ops[0], Ops[1], 0, 8, 1, 9, 2, 10, 3, 11, + "punpcklbw"); + case X86::BI__builtin_ia32_punpcklwd: + return EmitShuffleVector(Ops[0], Ops[1], 0, 4, 1, 5, "punpcklwd"); + case X86::BI__builtin_ia32_punpckldq: + return EmitShuffleVector(Ops[0], Ops[1], 0, 2, "punpckldq"); + case X86::BI__builtin_ia32_pslldi: + case X86::BI__builtin_ia32_psllqi: + case X86::BI__builtin_ia32_psllwi: + case X86::BI__builtin_ia32_psradi: + case X86::BI__builtin_ia32_psrawi: + case X86::BI__builtin_ia32_psrldi: + case X86::BI__builtin_ia32_psrlqi: + case X86::BI__builtin_ia32_psrlwi: { + Ops[1] = Builder.CreateZExt(Ops[1], llvm::Type::Int64Ty, "zext"); + const llvm::Type *Ty = llvm::VectorType::get(llvm::Type::Int64Ty, 1); + Ops[1] = Builder.CreateBitCast(Ops[1], Ty, "bitcast"); + const char *name = 0; + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + default: assert(0 && "Unsupported shift intrinsic!"); + case X86::BI__builtin_ia32_pslldi: + name = "pslldi"; + ID = Intrinsic::x86_mmx_psll_d; + break; + case X86::BI__builtin_ia32_psllqi: + name = "psllqi"; + ID = Intrinsic::x86_mmx_psll_q; + break; + case X86::BI__builtin_ia32_psllwi: + name = "psllwi"; + ID = Intrinsic::x86_mmx_psll_w; + break; + case X86::BI__builtin_ia32_psradi: + name = "psradi"; + ID = Intrinsic::x86_mmx_psra_d; + break; + case X86::BI__builtin_ia32_psrawi: + name = "psrawi"; + ID = Intrinsic::x86_mmx_psra_w; + break; + case X86::BI__builtin_ia32_psrldi: + name = "psrldi"; + ID = Intrinsic::x86_mmx_psrl_d; + break; + case X86::BI__builtin_ia32_psrlqi: + name = "psrlqi"; + ID = Intrinsic::x86_mmx_psrl_q; + break; + case X86::BI__builtin_ia32_psrlwi: + name = "psrlwi"; + ID = Intrinsic::x86_mmx_psrl_w; + break; + } + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); + } + case X86::BI__builtin_ia32_pshufd: { + unsigned i = cast(Ops[1])->getZExtValue(); + return EmitShuffleVector(Ops[0], Ops[0], + i & 0x3, (i & 0xc) >> 2, + (i & 0x30) >> 4, (i & 0xc0) >> 6, + "pshufd"); + } + case X86::BI__builtin_ia32_vec_init_v4hi: + case X86::BI__builtin_ia32_vec_init_v8qi: + case X86::BI__builtin_ia32_vec_init_v2si: + return EmitVector(&Ops[0], Ops.size()); + case X86::BI__builtin_ia32_vec_ext_v2si: + return Builder.CreateExtractElement(Ops[0], Ops[1], "result"); + case X86::BI__builtin_ia32_cmpordss: + case X86::BI__builtin_ia32_cmpunordss: + case X86::BI__builtin_ia32_cmpeqss: + case X86::BI__builtin_ia32_cmpltss: + case X86::BI__builtin_ia32_cmpless: + case X86::BI__builtin_ia32_cmpneqss: + case X86::BI__builtin_ia32_cmpnltss: + case X86::BI__builtin_ia32_cmpnless: { + unsigned i = 0; + const char *name = 0; + switch (BuiltinID) { + default: assert(0 && "Unknown compare builtin!"); + case X86::BI__builtin_ia32_cmpeqss: + i = 0; + name = "cmpeqss"; + break; + case X86::BI__builtin_ia32_cmpltss: + i = 1; + name = "cmpltss"; + break; + case X86::BI__builtin_ia32_cmpless: + i = 2; + name = "cmpless"; + break; + case X86::BI__builtin_ia32_cmpunordss: + i = 3; + name = "cmpunordss"; + break; + case X86::BI__builtin_ia32_cmpneqss: + i = 4; + name = "cmpneqss"; + break; + case X86::BI__builtin_ia32_cmpnltss: + i = 5; + name = "cmpntlss"; + break; + case X86::BI__builtin_ia32_cmpnless: + i = 6; + name = "cmpnless"; + break; + case X86::BI__builtin_ia32_cmpordss: + i = 7; + name = "cmpordss"; + break; + } + + Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i)); + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ss); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); + } + case X86::BI__builtin_ia32_cmpordps: + case X86::BI__builtin_ia32_cmpunordps: + case X86::BI__builtin_ia32_cmpeqps: + case X86::BI__builtin_ia32_cmpltps: + case X86::BI__builtin_ia32_cmpleps: + case X86::BI__builtin_ia32_cmpneqps: + case X86::BI__builtin_ia32_cmpngtps: + case X86::BI__builtin_ia32_cmpnltps: + case X86::BI__builtin_ia32_cmpgtps: + case X86::BI__builtin_ia32_cmpgeps: + case X86::BI__builtin_ia32_cmpngeps: + case X86::BI__builtin_ia32_cmpnleps: { + unsigned i = 0; + const char *name = 0; + bool ShouldSwap = false; + switch (BuiltinID) { + default: assert(0 && "Unknown compare builtin!"); + case X86::BI__builtin_ia32_cmpeqps: i = 0; name = "cmpeqps"; break; + case X86::BI__builtin_ia32_cmpltps: i = 1; name = "cmpltps"; break; + case X86::BI__builtin_ia32_cmpleps: i = 2; name = "cmpleps"; break; + case X86::BI__builtin_ia32_cmpunordps: i = 3; name = "cmpunordps"; break; + case X86::BI__builtin_ia32_cmpneqps: i = 4; name = "cmpneqps"; break; + case X86::BI__builtin_ia32_cmpnltps: i = 5; name = "cmpntlps"; break; + case X86::BI__builtin_ia32_cmpnleps: i = 6; name = "cmpnleps"; break; + case X86::BI__builtin_ia32_cmpordps: i = 7; name = "cmpordps"; break; + case X86::BI__builtin_ia32_cmpgtps: + ShouldSwap = true; + i = 1; + name = "cmpgtps"; + break; + case X86::BI__builtin_ia32_cmpgeps: + i = 2; + name = "cmpgeps"; + ShouldSwap = true; + break; + case X86::BI__builtin_ia32_cmpngtps: + i = 5; + name = "cmpngtps"; + ShouldSwap = true; + break; + case X86::BI__builtin_ia32_cmpngeps: + i = 6; + name = "cmpngeps"; + ShouldSwap = true; + break; + } + + if (ShouldSwap) + std::swap(Ops[0], Ops[1]); + + Ops.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, i)); + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse_cmp_ps); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); + } + case X86::BI__builtin_ia32_movss: + return EmitShuffleVector(Ops[0], Ops[1], 4, 1, 2, 3, "movss"); + case X86::BI__builtin_ia32_shufps: + unsigned i = cast(Ops[2])->getZExtValue(); + return EmitShuffleVector(Ops[0], Ops[1], + i & 0x3, (i & 0xc) >> 2, + ((i & 0x30) >> 4) + 4, + ((i & 0x60) >> 6) + 4, "shufps"); + } +} + +Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + switch (BuiltinID) { + default: return 0; + } +} diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp new file mode 100644 index 00000000000..c80cecc76ee --- /dev/null +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -0,0 +1,163 @@ +//===--- CGDecl.cpp - Emit LLVM Code for declarations ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Decl nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/AST.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Type.h" +using namespace clang; +using namespace CodeGen; + + +void CodeGenFunction::EmitDecl(const Decl &D) { + switch (D.getKind()) { + default: assert(0 && "Unknown decl kind!"); + case Decl::FileVar: + assert(0 && "Should not see file-scope variables inside a function!"); + case Decl::ParmVar: + assert(0 && "Parmdecls should not be in declstmts!"); + case Decl::Typedef: // typedef int X; + case Decl::Function: // void X(); + case Decl::Struct: // struct X; + case Decl::Union: // union X; + case Decl::Class: // class X; + case Decl::Enum: // enum X; + // None of these decls require codegen support. + return; + + case Decl::BlockVar: + return EmitBlockVarDecl(cast(D)); + case Decl::EnumConstant: + return EmitEnumConstantDecl(cast(D)); + } +} + +void CodeGenFunction::EmitEnumConstantDecl(const EnumConstantDecl &D) { + assert(0 && "FIXME: Enum constant decls not implemented yet!"); +} + +/// EmitBlockVarDecl - This method handles emission of any variable declaration +/// inside a function, including static vars etc. +void CodeGenFunction::EmitBlockVarDecl(const BlockVarDecl &D) { + switch (D.getStorageClass()) { + case VarDecl::Static: + return EmitStaticBlockVarDecl(D); + case VarDecl::Extern: + // Don't emit it now, allow it to be emitted lazily on its first use. + return; + default: + assert((D.getStorageClass() == VarDecl::None || + D.getStorageClass() == VarDecl::Auto || + D.getStorageClass() == VarDecl::Register) && + "Unknown storage class"); + return EmitLocalBlockVarDecl(D); + } +} + +void CodeGenFunction::EmitStaticBlockVarDecl(const BlockVarDecl &D) { + QualType Ty = D.getCanonicalType(); + assert(Ty->isConstantSizeType() && "VLAs can't be static"); + + llvm::Value *&DMEntry = LocalDeclMap[&D]; + assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); + + const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); + llvm::Constant *Init = 0; + if (D.getInit() == 0) { + Init = llvm::Constant::getNullValue(LTy); + } else { + Init = CGM.EmitConstantExpr(D.getInit(), this); + } + + assert(Init && "Unable to create initialiser for static decl"); + + std::string ContextName; + if (CurFuncDecl) + ContextName = CurFuncDecl->getName(); + else + assert(0 && "Unknown context for block var decl"); // FIXME Handle objc. + + DMEntry = + new llvm::GlobalVariable(LTy, false, + llvm::GlobalValue::InternalLinkage, + Init, ContextName + "." + D.getName(), + &CGM.getModule(), 0, + Ty.getAddressSpace()); + +} + +/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a +/// variable declaration with auto, register, or no storage class specifier. +/// These turn into simple stack objects. +void CodeGenFunction::EmitLocalBlockVarDecl(const BlockVarDecl &D) { + QualType Ty = D.getCanonicalType(); + + llvm::Value *DeclPtr; + if (Ty->isConstantSizeType()) { + // A normal fixed sized variable becomes an alloca in the entry block. + const llvm::Type *LTy = ConvertType(Ty); + // TODO: Alignment + DeclPtr = CreateTempAlloca(LTy, D.getName()); + } else { + // TODO: Create a dynamic alloca. + assert(0 && "FIXME: Local VLAs not implemented yet"); + } + + llvm::Value *&DMEntry = LocalDeclMap[&D]; + assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); + DMEntry = DeclPtr; + + // If this local has an initializer, emit it now. + if (const Expr *Init = D.getInit()) { + if (!hasAggregateLLVMType(Init->getType())) { + llvm::Value *V = EmitScalarExpr(Init); + Builder.CreateStore(V, DeclPtr, D.getType().isVolatileQualified()); + } else if (Init->getType()->isComplexType()) { + EmitComplexExprIntoAddr(Init, DeclPtr, D.getType().isVolatileQualified()); + } else { + EmitAggExpr(Init, DeclPtr, D.getType().isVolatileQualified()); + } + } +} + +/// Emit an alloca for the specified parameter and set up LocalDeclMap. +void CodeGenFunction::EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg) { + QualType Ty = D.getCanonicalType(); + + llvm::Value *DeclPtr; + if (!Ty->isConstantSizeType()) { + // Variable sized values always are passed by-reference. + DeclPtr = Arg; + } else { + // A fixed sized first class variable becomes an alloca in the entry block. + const llvm::Type *LTy = ConvertType(Ty); + if (LTy->isFirstClassType()) { + // TODO: Alignment + DeclPtr = new llvm::AllocaInst(LTy, 0, std::string(D.getName())+".addr", + AllocaInsertPt); + + // Store the initial value into the alloca. + Builder.CreateStore(Arg, DeclPtr); + } else { + // Otherwise, if this is an aggregate, just use the input pointer. + DeclPtr = Arg; + } + Arg->setName(D.getName()); + } + + llvm::Value *&DMEntry = LocalDeclMap[&D]; + assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); + DMEntry = DeclPtr; +} + diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp new file mode 100644 index 00000000000..932a5c5da8b --- /dev/null +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -0,0 +1,615 @@ +//===--- CGExpr.cpp - Emit LLVM Code from Expressions ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Expr nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/AST.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Support/MathExtras.h" +using namespace clang; +using namespace CodeGen; + +//===--------------------------------------------------------------------===// +// Miscellaneous Helper Methods +//===--------------------------------------------------------------------===// + +/// CreateTempAlloca - This creates a alloca and inserts it into the entry +/// block. +llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, + const char *Name) { + return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); +} + +/// EvaluateExprAsBool - Perform the usual unary conversions on the specified +/// expression and compare the result against zero, returning an Int1Ty value. +llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { + QualType BoolTy = getContext().BoolTy; + if (!E->getType()->isComplexType()) + return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); + + return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy); +} + +/// EmitAnyExpr - Emit code to compute the specified expression which can have +/// any type. The result is returned as an RValue struct. If this is an +/// aggregate expression, the aggloc/agglocvolatile arguments indicate where +/// the result should be returned. +RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc, + bool isAggLocVolatile) { + if (!hasAggregateLLVMType(E->getType())) + return RValue::get(EmitScalarExpr(E)); + else if (E->getType()->isComplexType()) + return RValue::getComplex(EmitComplexExpr(E)); + + EmitAggExpr(E, AggLoc, isAggLocVolatile); + return RValue::getAggregate(AggLoc); +} + + +//===----------------------------------------------------------------------===// +// LValue Expression Emission +//===----------------------------------------------------------------------===// + +/// EmitLValue - Emit code to compute a designator that specifies the location +/// of the expression. +/// +/// This can return one of two things: a simple address or a bitfield +/// reference. In either case, the LLVM Value* in the LValue structure is +/// guaranteed to be an LLVM pointer type. +/// +/// If this returns a bitfield reference, nothing about the pointee type of +/// the LLVM value is known: For example, it may not be a pointer to an +/// integer. +/// +/// If this returns a normal address, and if the lvalue's C type is fixed +/// size, this method guarantees that the returned pointer type will point to +/// an LLVM type of the same size of the lvalue's type. If the lvalue has a +/// variable length type, this is not possible. +/// +LValue CodeGenFunction::EmitLValue(const Expr *E) { + switch (E->getStmtClass()) { + default: { + WarnUnsupported(E, "l-value expression"); + llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); + return LValue::MakeAddr(llvm::UndefValue::get(Ty)); + } + + case Expr::CallExprClass: return EmitCallExprLValue(cast(E)); + case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast(E)); + case Expr::ParenExprClass:return EmitLValue(cast(E)->getSubExpr()); + case Expr::PreDefinedExprClass: + return EmitPreDefinedLValue(cast(E)); + case Expr::StringLiteralClass: + return EmitStringLiteralLValue(cast(E)); + + case Expr::UnaryOperatorClass: + return EmitUnaryOpLValue(cast(E)); + case Expr::ArraySubscriptExprClass: + return EmitArraySubscriptExpr(cast(E)); + case Expr::OCUVectorElementExprClass: + return EmitOCUVectorElementExpr(cast(E)); + case Expr::MemberExprClass: return EmitMemberExpr(cast(E)); + } +} + +/// EmitLoadOfLValue - Given an expression that represents a value lvalue, +/// this method emits the address of the lvalue, then loads the result as an +/// rvalue, returning the rvalue. +RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { + if (LV.isSimple()) { + llvm::Value *Ptr = LV.getAddress(); + const llvm::Type *EltTy = + cast(Ptr->getType())->getElementType(); + + // Simple scalar l-value. + if (EltTy->isFirstClassType()) { + llvm::Value *V = Builder.CreateLoad(Ptr, "tmp"); + + // Bool can have different representation in memory than in registers. + if (ExprType->isBooleanType()) { + if (V->getType() != llvm::Type::Int1Ty) + V = Builder.CreateTrunc(V, llvm::Type::Int1Ty, "tobool"); + } + + return RValue::get(V); + } + + assert(ExprType->isFunctionType() && "Unknown scalar value"); + return RValue::get(Ptr); + } + + if (LV.isVectorElt()) { + llvm::Value *Vec = Builder.CreateLoad(LV.getVectorAddr(), "tmp"); + return RValue::get(Builder.CreateExtractElement(Vec, LV.getVectorIdx(), + "vecext")); + } + + // If this is a reference to a subset of the elements of a vector, either + // shuffle the input or extract/insert them as appropriate. + if (LV.isOCUVectorElt()) + return EmitLoadOfOCUElementLValue(LV, ExprType); + + if (LV.isBitfield()) + return EmitLoadOfBitfieldLValue(LV, ExprType); + + assert(0 && "Unknown LValue type!"); + //an invalid RValue, but the assert will + //ensure that this point is never reached + return RValue(); +} + +RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, + QualType ExprType) { + llvm::Value *Ptr = LV.getBitfieldAddr(); + const llvm::Type *EltTy = + cast(Ptr->getType())->getElementType(); + unsigned EltTySize = EltTy->getPrimitiveSizeInBits(); + unsigned short BitfieldSize = LV.getBitfieldSize(); + unsigned short EndBit = LV.getBitfieldStartBit() + BitfieldSize; + + llvm::Value *V = Builder.CreateLoad(Ptr, "tmp"); + + llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - EndBit); + V = Builder.CreateShl(V, ShAmt, "tmp"); + + ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - BitfieldSize); + V = LV.isBitfieldSigned() ? + Builder.CreateAShr(V, ShAmt, "tmp") : + Builder.CreateLShr(V, ShAmt, "tmp"); + return RValue::get(V); +} + +// If this is a reference to a subset of the elements of a vector, either +// shuffle the input or extract/insert them as appropriate. +RValue CodeGenFunction::EmitLoadOfOCUElementLValue(LValue LV, + QualType ExprType) { + llvm::Value *Vec = Builder.CreateLoad(LV.getOCUVectorAddr(), "tmp"); + + unsigned EncFields = LV.getOCUVectorElts(); + + // If the result of the expression is a non-vector type, we must be + // extracting a single element. Just codegen as an extractelement. + const VectorType *ExprVT = ExprType->getAsVectorType(); + if (!ExprVT) { + unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields); + llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); + return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp")); + } + + // If the source and destination have the same number of elements, use a + // vector shuffle instead of insert/extracts. + unsigned NumResultElts = ExprVT->getNumElements(); + unsigned NumSourceElts = + cast(Vec->getType())->getNumElements(); + + if (NumResultElts == NumSourceElts) { + llvm::SmallVector Mask; + for (unsigned i = 0; i != NumResultElts; ++i) { + unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields); + Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); + } + + llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); + Vec = Builder.CreateShuffleVector(Vec, + llvm::UndefValue::get(Vec->getType()), + MaskV, "tmp"); + return RValue::get(Vec); + } + + // Start out with an undef of the result type. + llvm::Value *Result = llvm::UndefValue::get(ConvertType(ExprType)); + + // Extract/Insert each element of the result. + for (unsigned i = 0; i != NumResultElts; ++i) { + unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields); + llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); + Elt = Builder.CreateExtractElement(Vec, Elt, "tmp"); + + llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + Result = Builder.CreateInsertElement(Result, Elt, OutIdx, "tmp"); + } + + return RValue::get(Result); +} + + + +/// EmitStoreThroughLValue - Store the specified rvalue into the specified +/// lvalue, where both are guaranteed to the have the same type, and that type +/// is 'Ty'. +void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, + QualType Ty) { + if (!Dst.isSimple()) { + if (Dst.isVectorElt()) { + // Read/modify/write the vector, inserting the new element. + // FIXME: Volatility. + llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddr(), "tmp"); + Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), + Dst.getVectorIdx(), "vecins"); + Builder.CreateStore(Vec, Dst.getVectorAddr()); + return; + } + + // If this is an update of elements of a vector, insert them as appropriate. + if (Dst.isOCUVectorElt()) + return EmitStoreThroughOCUComponentLValue(Src, Dst, Ty); + + if (Dst.isBitfield()) + return EmitStoreThroughBitfieldLValue(Src, Dst, Ty); + + assert(0 && "Unknown LValue type"); + } + + llvm::Value *DstAddr = Dst.getAddress(); + assert(Src.isScalar() && "Can't emit an agg store with this method"); + // FIXME: Handle volatility etc. + const llvm::Type *SrcTy = Src.getScalarVal()->getType(); + const llvm::PointerType *DstPtr = cast(DstAddr->getType()); + const llvm::Type *AddrTy = DstPtr->getElementType(); + unsigned AS = DstPtr->getAddressSpace(); + + if (AddrTy != SrcTy) + DstAddr = Builder.CreateBitCast(DstAddr, + llvm::PointerType::get(SrcTy, AS), + "storetmp"); + Builder.CreateStore(Src.getScalarVal(), DstAddr); +} + +void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, + QualType Ty) { + unsigned short StartBit = Dst.getBitfieldStartBit(); + unsigned short BitfieldSize = Dst.getBitfieldSize(); + llvm::Value *Ptr = Dst.getBitfieldAddr(); + const llvm::Type *EltTy = + cast(Ptr->getType())->getElementType(); + unsigned EltTySize = EltTy->getPrimitiveSizeInBits(); + + llvm::Value *NewVal = Src.getScalarVal(); + llvm::Value *OldVal = Builder.CreateLoad(Ptr, "tmp"); + + llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, StartBit); + NewVal = Builder.CreateShl(NewVal, ShAmt, "tmp"); + + llvm::Constant *Mask = llvm::ConstantInt::get( + llvm::APInt::getBitsSet(EltTySize, StartBit, + StartBit + BitfieldSize)); + + // Mask out any bits that shouldn't be set in the result. + NewVal = Builder.CreateAnd(NewVal, Mask, "tmp"); + + // Next, mask out the bits this bit-field should include from the old value. + Mask = llvm::ConstantExpr::getNot(Mask); + OldVal = Builder.CreateAnd(OldVal, Mask, "tmp"); + + // Finally, merge the two together and store it. + NewVal = Builder.CreateOr(OldVal, NewVal, "tmp"); + + Builder.CreateStore(NewVal, Ptr); +} + +void CodeGenFunction::EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, + QualType Ty) { + // This access turns into a read/modify/write of the vector. Load the input + // value now. + llvm::Value *Vec = Builder.CreateLoad(Dst.getOCUVectorAddr(), "tmp"); + // FIXME: Volatility. + unsigned EncFields = Dst.getOCUVectorElts(); + + llvm::Value *SrcVal = Src.getScalarVal(); + + if (const VectorType *VTy = Ty->getAsVectorType()) { + unsigned NumSrcElts = VTy->getNumElements(); + + // Extract/Insert each element. + for (unsigned i = 0; i != NumSrcElts; ++i) { + llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp"); + + unsigned Idx = OCUVectorElementExpr::getAccessedFieldNo(i, EncFields); + llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx); + Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp"); + } + } else { + // If the Src is a scalar (not a vector) it must be updating one element. + unsigned InIdx = OCUVectorElementExpr::getAccessedFieldNo(0, EncFields); + llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); + Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); + } + + Builder.CreateStore(Vec, Dst.getOCUVectorAddr()); +} + + +LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { + const ValueDecl *D = E->getDecl(); + if (isa(D) || isa(D)) { + const VarDecl *VD = cast(D); + if (VD->getStorageClass() == VarDecl::Extern) + return LValue::MakeAddr(CGM.GetAddrOfGlobalVar(VD, false)); + else { + llvm::Value *V = LocalDeclMap[D]; + assert(V && "BlockVarDecl not entered in LocalDeclMap?"); + return LValue::MakeAddr(V); + } + } else if (const FunctionDecl *FD = dyn_cast(D)) { + return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false)); + } else if (const FileVarDecl *FVD = dyn_cast(D)) { + return LValue::MakeAddr(CGM.GetAddrOfGlobalVar(FVD, false)); + } + assert(0 && "Unimp declref"); + //an invalid LValue, but the assert will + //ensure that this point is never reached. + return LValue(); +} + +LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { + // __extension__ doesn't affect lvalue-ness. + if (E->getOpcode() == UnaryOperator::Extension) + return EmitLValue(E->getSubExpr()); + + switch (E->getOpcode()) { + default: assert(0 && "Unknown unary operator lvalue!"); + case UnaryOperator::Deref: + return LValue::MakeAddr(EmitScalarExpr(E->getSubExpr())); + case UnaryOperator::Real: + case UnaryOperator::Imag: + LValue LV = EmitLValue(E->getSubExpr()); + + llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, + E->getOpcode() == UnaryOperator::Imag); + llvm::Value *Ops[] = {Zero, Idx}; + return LValue::MakeAddr(Builder.CreateGEP(LV.getAddress(), Ops, Ops+2, + "idx")); + } +} + +LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { + assert(!E->isWide() && "FIXME: Wide strings not supported yet!"); + const char *StrData = E->getStrData(); + unsigned Len = E->getByteLength(); + std::string StringLiteral(StrData, StrData+Len); + return LValue::MakeAddr(CGM.GetAddrOfConstantString(StringLiteral)); +} + +LValue CodeGenFunction::EmitPreDefinedLValue(const PreDefinedExpr *E) { + std::string FunctionName(CurFuncDecl->getName()); + std::string GlobalVarName; + + switch (E->getIdentType()) { + default: + assert(0 && "unknown pre-defined ident type"); + case PreDefinedExpr::Func: + GlobalVarName = "__func__."; + break; + case PreDefinedExpr::Function: + GlobalVarName = "__FUNCTION__."; + break; + case PreDefinedExpr::PrettyFunction: + // FIXME:: Demangle C++ method names + GlobalVarName = "__PRETTY_FUNCTION__."; + break; + } + + GlobalVarName += CurFuncDecl->getName(); + + // FIXME: Can cache/reuse these within the module. + llvm::Constant *C=llvm::ConstantArray::get(FunctionName); + + // Create a global variable for this. + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, GlobalVarName, CurFn->getParent()); + return LValue::MakeAddr(C); +} + +LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { + // The index must always be an integer, which is not an aggregate. Emit it. + llvm::Value *Idx = EmitScalarExpr(E->getIdx()); + + // If the base is a vector type, then we are forming a vector element lvalue + // with this subscript. + if (E->getLHS()->getType()->isVectorType()) { + // Emit the vector as an lvalue to get its address. + LValue LHS = EmitLValue(E->getLHS()); + assert(LHS.isSimple() && "Can only subscript lvalue vectors here!"); + // FIXME: This should properly sign/zero/extend or truncate Idx to i32. + return LValue::MakeVectorElt(LHS.getAddress(), Idx); + } + + // The base must be a pointer, which is not an aggregate. Emit it. + llvm::Value *Base = EmitScalarExpr(E->getBase()); + + // Extend or truncate the index type to 32 or 64-bits. + QualType IdxTy = E->getIdx()->getType(); + bool IdxSigned = IdxTy->isSignedIntegerType(); + unsigned IdxBitwidth = cast(Idx->getType())->getBitWidth(); + if (IdxBitwidth != LLVMPointerWidth) + Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth), + IdxSigned, "idxprom"); + + // We know that the pointer points to a type of the correct size, unless the + // size is a VLA. + if (!E->getType()->isConstantSizeType()) + assert(0 && "VLA idx not implemented"); + return LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx")); +} + +LValue CodeGenFunction:: +EmitOCUVectorElementExpr(const OCUVectorElementExpr *E) { + // Emit the base vector as an l-value. + LValue Base = EmitLValue(E->getBase()); + assert(Base.isSimple() && "Can only subscript lvalue vectors here!"); + + return LValue::MakeOCUVectorElt(Base.getAddress(), + E->getEncodedElementAccess()); +} + +LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { + bool isUnion = false; + Expr *BaseExpr = E->getBase(); + llvm::Value *BaseValue = NULL; + + // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. + if (E->isArrow()) { + BaseValue = EmitScalarExpr(BaseExpr); + const PointerType *PTy = + cast(BaseExpr->getType().getCanonicalType()); + if (PTy->getPointeeType()->isUnionType()) + isUnion = true; + } + else { + LValue BaseLV = EmitLValue(BaseExpr); + // FIXME: this isn't right for bitfields. + BaseValue = BaseLV.getAddress(); + if (BaseExpr->getType()->isUnionType()) + isUnion = true; + } + + FieldDecl *Field = E->getMemberDecl(); + return EmitLValueForField(BaseValue, Field, isUnion); +} + +LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, + FieldDecl* Field, + bool isUnion) +{ + llvm::Value *V; + unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + + if (Field->isBitField()) { + const llvm::Type * FieldTy = ConvertType(Field->getType()); + const llvm::PointerType * BaseTy = + cast(BaseValue->getType()); + unsigned AS = BaseTy->getAddressSpace(); + BaseValue = Builder.CreateBitCast(BaseValue, + llvm::PointerType::get(FieldTy, AS), + "tmp"); + V = Builder.CreateGEP(BaseValue, + llvm::ConstantInt::get(llvm::Type::Int32Ty, idx), + "tmp"); + } else { + llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty), + llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) }; + V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp"); + } + // Match union field type. + if (isUnion) { + const llvm::Type * FieldTy = ConvertType(Field->getType()); + const llvm::PointerType * BaseTy = + cast(BaseValue->getType()); + if (FieldTy != BaseTy->getElementType()) { + unsigned AS = BaseTy->getAddressSpace(); + V = Builder.CreateBitCast(V, + llvm::PointerType::get(FieldTy, AS), + "tmp"); + } + } + + if (Field->isBitField()) { + CodeGenTypes::BitFieldInfo bitFieldInfo = + CGM.getTypes().getBitFieldInfo(Field); + return LValue::MakeBitfield(V, bitFieldInfo.Begin, bitFieldInfo.Size, + Field->getType()->isSignedIntegerType()); + } else + return LValue::MakeAddr(V); +} + +//===--------------------------------------------------------------------===// +// Expression Emission +//===--------------------------------------------------------------------===// + + +RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { + if (const ImplicitCastExpr *IcExpr = + dyn_cast(E->getCallee())) + if (const DeclRefExpr *DRExpr = + dyn_cast(IcExpr->getSubExpr())) + if (const FunctionDecl *FDecl = + dyn_cast(DRExpr->getDecl())) + if (unsigned builtinID = FDecl->getIdentifier()->getBuiltinID()) + return EmitBuiltinExpr(builtinID, E); + + llvm::Value *Callee = EmitScalarExpr(E->getCallee()); + return EmitCallExpr(Callee, E->getCallee()->getType(), + E->arg_begin(), E->getNumArgs()); +} + +RValue CodeGenFunction::EmitCallExpr(Expr *FnExpr, Expr *const *Args, + unsigned NumArgs) { + llvm::Value *Callee = EmitScalarExpr(FnExpr); + return EmitCallExpr(Callee, FnExpr->getType(), Args, NumArgs); +} + +LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { + // Can only get l-value for call expression returning aggregate type + RValue RV = EmitCallExpr(E); + return LValue::MakeAddr(RV.getAggregateAddr()); +} + +RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType, + Expr *const *ArgExprs, unsigned NumArgs) { + // The callee type will always be a pointer to function type, get the function + // type. + FnType = cast(FnType.getCanonicalType())->getPointeeType(); + QualType ResultType = cast(FnType)->getResultType(); + + llvm::SmallVector Args; + + // Handle struct-return functions by passing a pointer to the location that + // we would like to return into. + if (hasAggregateLLVMType(ResultType)) { + // Create a temporary alloca to hold the result of the call. :( + Args.push_back(CreateTempAlloca(ConvertType(ResultType))); + // FIXME: set the stret attribute on the argument. + } + + for (unsigned i = 0, e = NumArgs; i != e; ++i) { + QualType ArgTy = ArgExprs[i]->getType(); + + if (!hasAggregateLLVMType(ArgTy)) { + // Scalar argument is passed by-value. + Args.push_back(EmitScalarExpr(ArgExprs[i])); + } else if (ArgTy->isComplexType()) { + // Make a temporary alloca to pass the argument. + llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); + EmitComplexExprIntoAddr(ArgExprs[i], DestMem, false); + Args.push_back(DestMem); + } else { + llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); + EmitAggExpr(ArgExprs[i], DestMem, false); + Args.push_back(DestMem); + } + } + + llvm::CallInst *CI = Builder.CreateCall(Callee,&Args[0],&Args[0]+Args.size()); + if (const llvm::Function *F = dyn_cast(Callee)) + CI->setCallingConv(F->getCallingConv()); + if (CI->getType() != llvm::Type::VoidTy) + CI->setName("call"); + else if (ResultType->isComplexType()) + return RValue::getComplex(LoadComplexFromAddr(Args[0], false)); + else if (hasAggregateLLVMType(ResultType)) + // Struct return. + return RValue::getAggregate(Args[0]); + else { + // void return. + assert(ResultType->isVoidType() && "Should only have a void expr here"); + CI = 0; + } + + return RValue::get(CI); +} diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp new file mode 100644 index 00000000000..325ac2109eb --- /dev/null +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -0,0 +1,337 @@ +//===--- CGExprAgg.cpp - Emit LLVM Code from Aggregate Expressions --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Aggregate Expr nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/AST.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Support/Compiler.h" +using namespace clang; +using namespace CodeGen; + +//===----------------------------------------------------------------------===// +// Aggregate Expression Emitter +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor { + CodeGenFunction &CGF; + llvm::LLVMFoldingBuilder &Builder; + llvm::Value *DestPtr; + bool VolatileDest; +public: + AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool volatileDest) + : CGF(cgf), Builder(CGF.Builder), + DestPtr(destPtr), VolatileDest(volatileDest) { + } + + //===--------------------------------------------------------------------===// + // Utilities + //===--------------------------------------------------------------------===// + + /// EmitAggLoadOfLValue - Given an expression with aggregate type that + /// represents a value lvalue, this method emits the address of the lvalue, + /// then loads the result into DestPtr. + void EmitAggLoadOfLValue(const Expr *E); + + void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, + QualType EltTy); + + void EmitAggregateClear(llvm::Value *DestPtr, QualType Ty); + + void EmitNonConstInit(InitListExpr *E); + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + void VisitStmt(Stmt *S) { + CGF.WarnUnsupported(S, "aggregate expression"); + } + void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); } + + // l-values. + void VisitDeclRefExpr(DeclRefExpr *DRE) { EmitAggLoadOfLValue(DRE); } + void VisitMemberExpr(MemberExpr *ME) { EmitAggLoadOfLValue(ME); } + void VisitUnaryDeref(UnaryOperator *E) { EmitAggLoadOfLValue(E); } + void VisitStringLiteral(StringLiteral *E) { EmitAggLoadOfLValue(E); } + + void VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + EmitAggLoadOfLValue(E); + } + + // Operators. + // case Expr::UnaryOperatorClass: + // case Expr::CastExprClass: + void VisitImplicitCastExpr(ImplicitCastExpr *E); + void VisitCallExpr(const CallExpr *E); + void VisitStmtExpr(const StmtExpr *E); + void VisitBinaryOperator(const BinaryOperator *BO); + void VisitBinAssign(const BinaryOperator *E); + void VisitOverloadExpr(const OverloadExpr *E); + + + void VisitConditionalOperator(const ConditionalOperator *CO); + void VisitInitListExpr(InitListExpr *E); + // case Expr::ChooseExprClass: + +}; +} // end anonymous namespace. + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +void AggExprEmitter::EmitAggregateClear(llvm::Value *DestPtr, QualType Ty) { + assert(!Ty->isComplexType() && "Shouldn't happen for complex"); + + // Aggregate assignment turns into llvm.memset. + const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + if (DestPtr->getType() != BP) + DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); + + // Get size and alignment info for this aggregate. + std::pair TypeInfo = CGF.getContext().getTypeInfo(Ty); + + // FIXME: Handle variable sized types. + const llvm::Type *IntPtr = llvm::IntegerType::get(CGF.LLVMPointerWidth); + + llvm::Value *MemSetOps[4] = { + DestPtr, + llvm::ConstantInt::getNullValue(llvm::Type::Int8Ty), + // TypeInfo.first describes size in bits. + llvm::ConstantInt::get(IntPtr, TypeInfo.first/8), + llvm::ConstantInt::get(llvm::Type::Int32Ty, TypeInfo.second/8) + }; + + Builder.CreateCall(CGF.CGM.getMemSetFn(), MemSetOps, MemSetOps+4); +} + +void AggExprEmitter::EmitAggregateCopy(llvm::Value *DestPtr, + llvm::Value *SrcPtr, QualType Ty) { + assert(!Ty->isComplexType() && "Shouldn't happen for complex"); + + // Aggregate assignment turns into llvm.memcpy. + const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + if (DestPtr->getType() != BP) + DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); + if (SrcPtr->getType() != BP) + SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + + // Get size and alignment info for this aggregate. + std::pair TypeInfo = CGF.getContext().getTypeInfo(Ty); + + // FIXME: Handle variable sized types. + const llvm::Type *IntPtr = llvm::IntegerType::get(CGF.LLVMPointerWidth); + + llvm::Value *MemCpyOps[4] = { + DestPtr, SrcPtr, + // TypeInfo.first describes size in bits. + llvm::ConstantInt::get(IntPtr, TypeInfo.first/8), + llvm::ConstantInt::get(llvm::Type::Int32Ty, TypeInfo.second/8) + }; + + Builder.CreateCall(CGF.CGM.getMemCpyFn(), MemCpyOps, MemCpyOps+4); +} + + +/// EmitAggLoadOfLValue - Given an expression with aggregate type that +/// represents a value lvalue, this method emits the address of the lvalue, +/// then loads the result into DestPtr. +void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) { + LValue LV = CGF.EmitLValue(E); + assert(LV.isSimple() && "Can't have aggregate bitfield, vector, etc"); + llvm::Value *SrcPtr = LV.getAddress(); + + // If the result is ignored, don't copy from the value. + if (DestPtr == 0) + // FIXME: If the source is volatile, we must read from it. + return; + + EmitAggregateCopy(DestPtr, SrcPtr, E->getType()); +} + +//===----------------------------------------------------------------------===// +// Visitor Methods +//===----------------------------------------------------------------------===// + +void AggExprEmitter::VisitImplicitCastExpr(ImplicitCastExpr *E) +{ + QualType STy = E->getSubExpr()->getType().getCanonicalType(); + QualType Ty = E->getType().getCanonicalType(); + + assert(CGF.getContext().typesAreCompatible( + STy.getUnqualifiedType(), Ty.getUnqualifiedType()) + && "Implicit cast types must be compatible"); + + Visit(E->getSubExpr()); +} + +void AggExprEmitter::VisitCallExpr(const CallExpr *E) +{ + RValue RV = CGF.EmitCallExpr(E); + assert(RV.isAggregate() && "Return value must be aggregate value!"); + + // If the result is ignored, don't copy from the value. + if (DestPtr == 0) + // FIXME: If the source is volatile, we must read from it. + return; + + EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType()); +} + +void AggExprEmitter::VisitOverloadExpr(const OverloadExpr *E) +{ + RValue RV = CGF.EmitCallExpr(E->getFn(), E->arg_begin(), + E->getNumArgs(CGF.getContext())); + assert(RV.isAggregate() && "Return value must be aggregate value!"); + + // If the result is ignored, don't copy from the value. + if (DestPtr == 0) + // FIXME: If the source is volatile, we must read from it. + return; + + EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType()); +} + +void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { + CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest); +} + +void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { + CGF.WarnUnsupported(E, "aggregate binary expression"); +} + +void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { + // For an assignment to work, the value on the right has + // to be compatible with the value on the left. + assert(CGF.getContext().typesAreCompatible( + E->getLHS()->getType().getUnqualifiedType(), + E->getRHS()->getType().getUnqualifiedType()) + && "Invalid assignment"); + LValue LHS = CGF.EmitLValue(E->getLHS()); + + // Codegen the RHS so that it stores directly into the LHS. + CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), false /*FIXME: VOLATILE LHS*/); + + if (DestPtr == 0) + return; + + // If the result of the assignment is used, copy the RHS there also. + EmitAggregateCopy(DestPtr, LHS.getAddress(), E->getType()); +} + +void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { + llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?"); + llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:"); + llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont"); + + llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); + Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + + CGF.EmitBlock(LHSBlock); + + // Handle the GNU extension for missing LHS. + assert(E->getLHS() && "Must have LHS for aggregate value"); + + Visit(E->getLHS()); + Builder.CreateBr(ContBlock); + LHSBlock = Builder.GetInsertBlock(); + + CGF.EmitBlock(RHSBlock); + + Visit(E->getRHS()); + Builder.CreateBr(ContBlock); + RHSBlock = Builder.GetInsertBlock(); + + CGF.EmitBlock(ContBlock); +} + +void AggExprEmitter::EmitNonConstInit(InitListExpr *E) { + + const llvm::PointerType *APType = + cast(DestPtr->getType()); + const llvm::Type *DestType = APType->getElementType(); + + if (const llvm::ArrayType *AType = dyn_cast(DestType)) { + unsigned NumInitElements = E->getNumInits(); + + llvm::Value *Idxs[] = { + llvm::Constant::getNullValue(llvm::Type::Int32Ty), + NULL + }; + llvm::Value *NextVal = NULL; + unsigned i; + for (i = 0; i != NumInitElements; ++i) { + Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2,".array"); + Expr *Init = E->getInit(i); + if (isa(Init)) + CGF.EmitAggExpr(Init, NextVal, VolatileDest); + else + Builder.CreateStore(CGF.EmitScalarExpr(Init), NextVal); + } + + // Emit remaining default initializers + unsigned NumArrayElements = AType->getNumElements(); + QualType QType = E->getInit(0)->getType(); + const llvm::Type *EType = AType->getElementType(); + for (/*Do not initialize i*/; i < NumArrayElements; ++i) { + Idxs[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + NextVal = Builder.CreateGEP(DestPtr, Idxs, Idxs + 2,".array"); + if (EType->isFirstClassType()) + Builder.CreateStore(llvm::Constant::getNullValue(EType), NextVal); + else + EmitAggregateClear(NextVal, QType); + } + } else + assert(false && "Invalid initializer"); +} + +void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { + + if (E->isConstantExpr(CGF.CGM.getContext(), NULL)) { + llvm::Constant *V = CGF.CGM.EmitConstantExpr(E); + // Create global value to hold this array. + V = new llvm::GlobalVariable(V->getType(), true, + llvm::GlobalValue::InternalLinkage, + V, ".array", + &CGF.CGM.getModule()); + + EmitAggregateCopy(DestPtr, V , E->getType()); + return; + } else { + if (!E->getType()->isArrayType()) { + CGF.WarnUnsupported(E, "aggregate init-list expression"); + return; + } + EmitNonConstInit(E); + } +} + +//===----------------------------------------------------------------------===// +// Entry Points into this File +//===----------------------------------------------------------------------===// + +/// EmitAggExpr - Emit the computation of the specified expression of +/// aggregate type. The result is computed into DestPtr. Note that if +/// DestPtr is null, the value of the aggregate expression is not needed. +void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, + bool VolatileDest) { + assert(E && hasAggregateLLVMType(E->getType()) && + "Invalid aggregate expression to emit"); + + AggExprEmitter(*this, DestPtr, VolatileDest).Visit(const_cast(E)); +} diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp new file mode 100644 index 00000000000..b1de93570d9 --- /dev/null +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -0,0 +1,542 @@ +//===--- CGExprComplex.cpp - Emit LLVM Code for Complex Exprs -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Expr nodes with complex types as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/AST.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Compiler.h" +using namespace clang; +using namespace CodeGen; + +//===----------------------------------------------------------------------===// +// Complex Expression Emitter +//===----------------------------------------------------------------------===// + +typedef CodeGenFunction::ComplexPairTy ComplexPairTy; + +namespace { +class VISIBILITY_HIDDEN ComplexExprEmitter + : public StmtVisitor { + CodeGenFunction &CGF; + llvm::LLVMFoldingBuilder &Builder; +public: + ComplexExprEmitter(CodeGenFunction &cgf) : CGF(cgf), Builder(CGF.Builder) { + } + + + //===--------------------------------------------------------------------===// + // Utilities + //===--------------------------------------------------------------------===// + + /// EmitLoadOfLValue - Given an expression with complex type that represents a + /// value l-value, this method emits the address of the l-value, then loads + /// and returns the result. + ComplexPairTy EmitLoadOfLValue(const Expr *E) { + LValue LV = CGF.EmitLValue(E); + // FIXME: Volatile + return EmitLoadOfComplex(LV.getAddress(), false); + } + + /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load + /// the real and imaginary pieces. + ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile); + + /// EmitStoreOfComplex - Store the specified real/imag parts into the + /// specified value pointer. + void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol); + + /// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. + ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType, + QualType DestType); + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + ComplexPairTy VisitStmt(Stmt *S) { + S->dump(CGF.getContext().getSourceManager()); + assert(0 && "Stmt can't have complex result type!"); + return ComplexPairTy(); + } + ComplexPairTy VisitExpr(Expr *S); + ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());} + ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL); + + // l-values. + ComplexPairTy VisitDeclRefExpr(const Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); } + + // FIXME: CompoundLiteralExpr + + ComplexPairTy EmitCast(Expr *Op, QualType DestTy); + ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) { + // Unlike for scalars, we don't have to worry about function->ptr demotion + // here. + return EmitCast(E->getSubExpr(), E->getType()); + } + ComplexPairTy VisitCastExpr(CastExpr *E) { + return EmitCast(E->getSubExpr(), E->getType()); + } + ComplexPairTy VisitCallExpr(const CallExpr *E); + ComplexPairTy VisitStmtExpr(const StmtExpr *E); + ComplexPairTy VisitOverloadExpr(const OverloadExpr *OE); + + // Operators. + ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E, + bool isInc, bool isPre); + ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) { + return VisitPrePostIncDec(E, false, false); + } + ComplexPairTy VisitUnaryPostInc(const UnaryOperator *E) { + return VisitPrePostIncDec(E, true, false); + } + ComplexPairTy VisitUnaryPreDec(const UnaryOperator *E) { + return VisitPrePostIncDec(E, false, true); + } + ComplexPairTy VisitUnaryPreInc(const UnaryOperator *E) { + return VisitPrePostIncDec(E, true, true); + } + ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); } + ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + ComplexPairTy VisitUnaryMinus (const UnaryOperator *E); + ComplexPairTy VisitUnaryNot (const UnaryOperator *E); + // LNot,SizeOf,AlignOf,Real,Imag never return complex. + ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + + struct BinOpInfo { + ComplexPairTy LHS; + ComplexPairTy RHS; + QualType Ty; // Computation Type. + }; + + BinOpInfo EmitBinOps(const BinaryOperator *E); + ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E, + ComplexPairTy (ComplexExprEmitter::*Func) + (const BinOpInfo &)); + + ComplexPairTy EmitBinAdd(const BinOpInfo &Op); + ComplexPairTy EmitBinSub(const BinOpInfo &Op); + ComplexPairTy EmitBinMul(const BinOpInfo &Op); + ComplexPairTy EmitBinDiv(const BinOpInfo &Op); + + ComplexPairTy VisitBinMul(const BinaryOperator *E) { + return EmitBinMul(EmitBinOps(E)); + } + ComplexPairTy VisitBinAdd(const BinaryOperator *E) { + return EmitBinAdd(EmitBinOps(E)); + } + ComplexPairTy VisitBinSub(const BinaryOperator *E) { + return EmitBinSub(EmitBinOps(E)); + } + ComplexPairTy VisitBinDiv(const BinaryOperator *E) { + return EmitBinDiv(EmitBinOps(E)); + } + + // Compound assignments. + ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) { + return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd); + } + ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) { + return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub); + } + ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) { + return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul); + } + ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) { + return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv); + } + + // GCC rejects rem/and/or/xor for integer complex. + // Logical and/or always return int, never complex. + + // No comparisons produce a complex result. + ComplexPairTy VisitBinAssign (const BinaryOperator *E); + ComplexPairTy VisitBinComma (const BinaryOperator *E); + + + ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO); + ComplexPairTy VisitChooseExpr(ChooseExpr *CE); +}; +} // end anonymous namespace. + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to +/// load the real and imaginary pieces, returning them as Real/Imag. +ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr, + bool isVolatile) { + llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1); + + llvm::SmallString<64> Name(SrcPtr->getNameStart(), + SrcPtr->getNameStart()+SrcPtr->getNameLen()); + + Name += ".realp"; + llvm::Value *Ops[] = {Zero, Zero}; + llvm::Value *RealPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str()); + + Name.pop_back(); // .realp -> .real + llvm::Value *Real = Builder.CreateLoad(RealPtr, isVolatile, Name.c_str()); + + Name.resize(Name.size()-4); // .real -> .imagp + Name += "imagp"; + + Ops[1] = One; // { Ops = { Zero, One } + llvm::Value *ImagPtr = Builder.CreateGEP(SrcPtr, Ops, Ops+2, Name.c_str()); + + Name.pop_back(); // .imagp -> .imag + llvm::Value *Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.c_str()); + return ComplexPairTy(Real, Imag); +} + +/// EmitStoreOfComplex - Store the specified real/imag parts into the +/// specified value pointer. +void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr, + bool isVolatile) { + llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *One = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1); + + llvm::Value *Ops[] = {Zero, Zero}; + llvm::Value *RealPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "real"); + + Ops[1] = One; // { Ops = { Zero, One } + llvm::Value *ImagPtr = Builder.CreateGEP(Ptr, Ops, Ops+2, "imag"); + + Builder.CreateStore(Val.first, RealPtr, isVolatile); + Builder.CreateStore(Val.second, ImagPtr, isVolatile); +} + + + +//===----------------------------------------------------------------------===// +// Visitor Methods +//===----------------------------------------------------------------------===// + +ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) { + CGF.WarnUnsupported(E, "complex expression"); + const llvm::Type *EltTy = + CGF.ConvertType(E->getType()->getAsComplexType()->getElementType()); + llvm::Value *U = llvm::UndefValue::get(EltTy); + return ComplexPairTy(U, U); +} + +ComplexPairTy ComplexExprEmitter:: +VisitImaginaryLiteral(const ImaginaryLiteral *IL) { + llvm::Value *Imag = CGF.EmitScalarExpr(IL->getSubExpr()); + return ComplexPairTy(llvm::Constant::getNullValue(Imag->getType()), Imag); +} + + +ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) { + return CGF.EmitCallExpr(E).getComplexVal(); +} + +ComplexPairTy ComplexExprEmitter::VisitOverloadExpr(const OverloadExpr *E) { + return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), + E->getNumArgs(CGF.getContext())).getComplexVal(); +} + +ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) { + return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal(); +} + +/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType. +ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val, + QualType SrcType, + QualType DestType) { + // Get the src/dest element type. + SrcType = cast(SrcType.getCanonicalType())->getElementType(); + DestType = cast(DestType.getCanonicalType())->getElementType(); + + // C99 6.3.1.6: When a value of complextype is converted to another + // complex type, both the real and imaginary parts followthe conversion + // rules for the corresponding real types. + Val.first = CGF.EmitScalarConversion(Val.first, SrcType, DestType); + Val.second = CGF.EmitScalarConversion(Val.second, SrcType, DestType); + return Val; +} + +ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) { + // Two cases here: cast from (complex to complex) and (scalar to complex). + if (Op->getType()->isComplexType()) + return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy); + + // C99 6.3.1.7: When a value of real type is converted to a complex type, the + // real part of the complex result value is determined by the rules of + // conversion to the corresponding real type and the imaginary part of the + // complex result value is a positive zero or an unsigned zero. + llvm::Value *Elt = CGF.EmitScalarExpr(Op); + + // Convert the input element to the element type of the complex. + DestTy = cast(DestTy.getCanonicalType())->getElementType(); + Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy); + + // Return (realval, 0). + return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType())); +} + +ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, + bool isInc, bool isPre) { + LValue LV = CGF.EmitLValue(E->getSubExpr()); + // FIXME: Handle volatile! + ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), false); + + uint64_t AmountVal = isInc ? 1 : -1; + + llvm::Value *NextVal; + if (isa(InVal.first->getType())) + NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal); + else if (InVal.first->getType() == llvm::Type::FloatTy) + // FIXME: Handle long double. + NextVal = + llvm::ConstantFP::get(InVal.first->getType(), + llvm::APFloat(static_cast(AmountVal))); + else { + // FIXME: Handle long double. + assert(InVal.first->getType() == llvm::Type::DoubleTy); + NextVal = + llvm::ConstantFP::get(InVal.first->getType(), + llvm::APFloat(static_cast(AmountVal))); + } + + // Add the inc/dec to the real part. + NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); + + ComplexPairTy IncVal(NextVal, InVal.second); + + // Store the updated result through the lvalue. + EmitStoreOfComplex(IncVal, LV.getAddress(), false); /* FIXME: Volatile */ + + // If this is a postinc, return the value read from memory, otherwise use the + // updated value. + return isPre ? IncVal : InVal; +} + +ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { + ComplexPairTy Op = Visit(E->getSubExpr()); + llvm::Value *ResR = Builder.CreateNeg(Op.first, "neg.r"); + llvm::Value *ResI = Builder.CreateNeg(Op.second, "neg.i"); + return ComplexPairTy(ResR, ResI); +} + +ComplexPairTy ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *E) { + // ~(a+ib) = a + i*-b + ComplexPairTy Op = Visit(E->getSubExpr()); + llvm::Value *ResI = Builder.CreateNeg(Op.second, "conj.i"); + return ComplexPairTy(Op.first, ResI); +} + +ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) { + llvm::Value *ResR = Builder.CreateAdd(Op.LHS.first, Op.RHS.first, "add.r"); + llvm::Value *ResI = Builder.CreateAdd(Op.LHS.second, Op.RHS.second, "add.i"); + return ComplexPairTy(ResR, ResI); +} + +ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) { + llvm::Value *ResR = Builder.CreateSub(Op.LHS.first, Op.RHS.first, "sub.r"); + llvm::Value *ResI = Builder.CreateSub(Op.LHS.second, Op.RHS.second, "sub.i"); + return ComplexPairTy(ResR, ResI); +} + + +ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) { + llvm::Value *ResRl = Builder.CreateMul(Op.LHS.first, Op.RHS.first, "mul.rl"); + llvm::Value *ResRr = Builder.CreateMul(Op.LHS.second, Op.RHS.second,"mul.rr"); + llvm::Value *ResR = Builder.CreateSub(ResRl, ResRr, "mul.r"); + + llvm::Value *ResIl = Builder.CreateMul(Op.LHS.second, Op.RHS.first, "mul.il"); + llvm::Value *ResIr = Builder.CreateMul(Op.LHS.first, Op.RHS.second, "mul.ir"); + llvm::Value *ResI = Builder.CreateAdd(ResIl, ResIr, "mul.i"); + return ComplexPairTy(ResR, ResI); +} + +ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { + llvm::Value *LHSr = Op.LHS.first, *LHSi = Op.LHS.second; + llvm::Value *RHSr = Op.RHS.first, *RHSi = Op.RHS.second; + + // (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) + llvm::Value *Tmp1 = Builder.CreateMul(LHSr, RHSr, "tmp"); // a*c + llvm::Value *Tmp2 = Builder.CreateMul(LHSi, RHSi, "tmp"); // b*d + llvm::Value *Tmp3 = Builder.CreateAdd(Tmp1, Tmp2, "tmp"); // ac+bd + + llvm::Value *Tmp4 = Builder.CreateMul(RHSr, RHSr, "tmp"); // c*c + llvm::Value *Tmp5 = Builder.CreateMul(RHSi, RHSi, "tmp"); // d*d + llvm::Value *Tmp6 = Builder.CreateAdd(Tmp4, Tmp5, "tmp"); // cc+dd + + llvm::Value *Tmp7 = Builder.CreateMul(LHSi, RHSr, "tmp"); // b*c + llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi, "tmp"); // a*d + llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8, "tmp"); // bc-ad + + llvm::Value *DSTr, *DSTi; + if (Tmp3->getType()->isFloatingPoint()) { + DSTr = Builder.CreateFDiv(Tmp3, Tmp6, "tmp"); + DSTi = Builder.CreateFDiv(Tmp9, Tmp6, "tmp"); + } else { + if (Op.Ty->getAsComplexType()->getElementType()->isUnsignedIntegerType()) { + DSTr = Builder.CreateUDiv(Tmp3, Tmp6, "tmp"); + DSTi = Builder.CreateUDiv(Tmp9, Tmp6, "tmp"); + } else { + DSTr = Builder.CreateSDiv(Tmp3, Tmp6, "tmp"); + DSTi = Builder.CreateSDiv(Tmp9, Tmp6, "tmp"); + } + } + + return ComplexPairTy(DSTr, DSTi); +} + +ComplexExprEmitter::BinOpInfo +ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) { + BinOpInfo Ops; + Ops.LHS = Visit(E->getLHS()); + Ops.RHS = Visit(E->getRHS()); + Ops.Ty = E->getType(); + return Ops; +} + + +// Compound assignments. +ComplexPairTy ComplexExprEmitter:: +EmitCompoundAssign(const CompoundAssignOperator *E, + ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){ + QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType(); + + // Load the LHS and RHS operands. + LValue LHSLV = CGF.EmitLValue(E->getLHS()); + + BinOpInfo OpInfo; + OpInfo.Ty = E->getComputationType(); + + // We know the LHS is a complex lvalue. + OpInfo.LHS = EmitLoadOfComplex(LHSLV.getAddress(), false);// FIXME: Volatile. + OpInfo.LHS = EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty); + + // It is possible for the RHS to be complex or scalar. + OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty); + + // Expand the binary operator. + ComplexPairTy Result = (this->*Func)(OpInfo); + + // Truncate the result back to the LHS type. + Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy); + + // Store the result value into the LHS lvalue. + EmitStoreOfComplex(Result, LHSLV.getAddress(), false); // FIXME: VOLATILE + return Result; +} + +ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { + assert(E->getLHS()->getType().getCanonicalType() == + E->getRHS()->getType().getCanonicalType() && "Invalid assignment"); + // Emit the RHS. + ComplexPairTy Val = Visit(E->getRHS()); + + // Compute the address to store into. + LValue LHS = CGF.EmitLValue(E->getLHS()); + + // Store into it. + // FIXME: Volatility! + EmitStoreOfComplex(Val, LHS.getAddress(), false); + return Val; +} + +ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) { + CGF.EmitStmt(E->getLHS()); + return Visit(E->getRHS()); +} + +ComplexPairTy ComplexExprEmitter:: +VisitConditionalOperator(const ConditionalOperator *E) { + llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?"); + llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:"); + llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont"); + + llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); + Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + + CGF.EmitBlock(LHSBlock); + + // Handle the GNU extension for missing LHS. + assert(E->getLHS() && "Must have LHS for complex value"); + + ComplexPairTy LHS = Visit(E->getLHS()); + Builder.CreateBr(ContBlock); + LHSBlock = Builder.GetInsertBlock(); + + CGF.EmitBlock(RHSBlock); + + ComplexPairTy RHS = Visit(E->getRHS()); + Builder.CreateBr(ContBlock); + RHSBlock = Builder.GetInsertBlock(); + + CGF.EmitBlock(ContBlock); + + // Create a PHI node for the real part. + llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r"); + RealPN->reserveOperandSpace(2); + RealPN->addIncoming(LHS.first, LHSBlock); + RealPN->addIncoming(RHS.first, RHSBlock); + + // Create a PHI node for the imaginary part. + llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i"); + ImagPN->reserveOperandSpace(2); + ImagPN->addIncoming(LHS.second, LHSBlock); + ImagPN->addIncoming(RHS.second, RHSBlock); + + return ComplexPairTy(RealPN, ImagPN); +} + +ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) { + // Emit the LHS or RHS as appropriate. + return Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() :E->getRHS()); +} + +//===----------------------------------------------------------------------===// +// Entry Point into this File +//===----------------------------------------------------------------------===// + +/// EmitComplexExpr - Emit the computation of the specified expression of +/// complex type, ignoring the result. +ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E) { + assert(E && E->getType()->isComplexType() && + "Invalid complex expression to emit"); + + return ComplexExprEmitter(*this).Visit(const_cast(E)); +} + +/// EmitComplexExprIntoAddr - Emit the computation of the specified expression +/// of complex type, storing into the specified Value*. +void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E, + llvm::Value *DestAddr, + bool DestIsVolatile) { + assert(E && E->getType()->isComplexType() && + "Invalid complex expression to emit"); + ComplexExprEmitter Emitter(*this); + ComplexPairTy Val = Emitter.Visit(const_cast(E)); + Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile); +} + +/// LoadComplexFromAddr - Load a complex number from the specified address. +ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr, + bool SrcIsVolatile) { + return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile); +} diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp new file mode 100644 index 00000000000..e2405b88f37 --- /dev/null +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -0,0 +1,627 @@ +//===--- CGExprConstant.cpp - Emit LLVM Code from Constant Expressions ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Constant Expr nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/AST.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Support/Compiler.h" +using namespace clang; +using namespace CodeGen; + +namespace { +class VISIBILITY_HIDDEN ConstExprEmitter : + public StmtVisitor { + CodeGenModule &CGM; + CodeGenFunction *CGF; +public: + ConstExprEmitter(CodeGenModule &cgm, CodeGenFunction *cgf) + : CGM(cgm), CGF(cgf) { + } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + llvm::Constant *VisitStmt(Stmt *S) { + CGM.WarnUnsupported(S, "constant expression"); + QualType T = cast(S)->getType(); + return llvm::UndefValue::get(CGM.getTypes().ConvertType(T)); + } + + llvm::Constant *VisitParenExpr(ParenExpr *PE) { + return Visit(PE->getSubExpr()); + } + + // Leaves + llvm::Constant *VisitIntegerLiteral(const IntegerLiteral *E) { + return llvm::ConstantInt::get(E->getValue()); + } + llvm::Constant *VisitFloatingLiteral(const FloatingLiteral *E) { + return llvm::ConstantFP::get(ConvertType(E->getType()), E->getValue()); + } + llvm::Constant *VisitCharacterLiteral(const CharacterLiteral *E) { + return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); + } + llvm::Constant *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { + return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); + } + + llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + return Visit(E->getInitializer()); + } + + llvm::Constant *VisitCastExpr(const CastExpr* E) { + llvm::Constant *C = Visit(E->getSubExpr()); + + return EmitConversion(C, E->getSubExpr()->getType(), E->getType()); + } + + llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, + const llvm::ArrayType *AType) { + std::vector Elts; + unsigned NumInitElements = ILE->getNumInits(); + // FIXME: Check for wide strings + if (NumInitElements > 0 && isa(ILE->getInit(0)) && + ILE->getType()->getAsArrayType()->getElementType()->isCharType()) + return Visit(ILE->getInit(0)); + const llvm::Type *ElemTy = AType->getElementType(); + unsigned NumElements = AType->getNumElements(); + + // Initialising an array requires us to automatically + // initialise any elements that have not been initialised explicitly + unsigned NumInitableElts = std::min(NumInitElements, NumElements); + + // Copy initializer elements. + unsigned i = 0; + for (; i < NumInitableElts; ++i) { + + llvm::Constant *C = Visit(ILE->getInit(i)); + // FIXME: Remove this when sema of initializers is finished (and the code + // above). + if (C == 0 && ILE->getInit(i)->getType()->isVoidType()) { + if (ILE->getType()->isVoidType()) return 0; + return llvm::UndefValue::get(AType); + } + assert (C && "Failed to create initializer expression"); + Elts.push_back(C); + } + + // Initialize remaining array elements. + for (; i < NumElements; ++i) + Elts.push_back(llvm::Constant::getNullValue(ElemTy)); + + return llvm::ConstantArray::get(AType, Elts); + } + + llvm::Constant *EmitStructInitialization(InitListExpr *ILE, + const llvm::StructType *SType) { + + TagDecl *TD = ILE->getType()->getAsRecordType()->getDecl(); + std::vector Elts; + const CGRecordLayout *CGR = CGM.getTypes().getCGRecordLayout(TD); + unsigned NumInitElements = ILE->getNumInits(); + unsigned NumElements = SType->getNumElements(); + + // Initialising an structure requires us to automatically + // initialise any elements that have not been initialised explicitly + unsigned NumInitableElts = std::min(NumInitElements, NumElements); + + // Copy initializer elements. Skip padding fields. + unsigned EltNo = 0; // Element no in ILE + unsigned FieldNo = 0; // Field no in SType + while (EltNo < NumInitableElts) { + + // Zero initialize padding field. + if (CGR->isPaddingField(FieldNo)) { + const llvm::Type *FieldTy = SType->getElementType(FieldNo); + Elts.push_back(llvm::Constant::getNullValue(FieldTy)); + FieldNo++; + continue; + } + + llvm::Constant *C = Visit(ILE->getInit(EltNo)); + // FIXME: Remove this when sema of initializers is finished (and the code + // above). + if (C == 0 && ILE->getInit(EltNo)->getType()->isVoidType()) { + if (ILE->getType()->isVoidType()) return 0; + return llvm::UndefValue::get(SType); + } + assert (C && "Failed to create initializer expression"); + Elts.push_back(C); + EltNo++; + FieldNo++; + } + + // Initialize remaining structure elements. + for (unsigned i = Elts.size(); i < NumElements; ++i) { + const llvm::Type *FieldTy = SType->getElementType(i); + Elts.push_back(llvm::Constant::getNullValue(FieldTy)); + } + + return llvm::ConstantStruct::get(SType, Elts); + } + + llvm::Constant *EmitVectorInitialization(InitListExpr *ILE, + const llvm::VectorType *VType) { + + std::vector Elts; + unsigned NumInitElements = ILE->getNumInits(); + unsigned NumElements = VType->getNumElements(); + + assert (NumInitElements == NumElements + && "Unsufficient vector init elelments"); + // Copy initializer elements. + unsigned i = 0; + for (; i < NumElements; ++i) { + + llvm::Constant *C = Visit(ILE->getInit(i)); + // FIXME: Remove this when sema of initializers is finished (and the code + // above). + if (C == 0 && ILE->getInit(i)->getType()->isVoidType()) { + if (ILE->getType()->isVoidType()) return 0; + return llvm::UndefValue::get(VType); + } + assert (C && "Failed to create initializer expression"); + Elts.push_back(C); + } + + return llvm::ConstantVector::get(VType, Elts); + } + + llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { + const llvm::CompositeType *CType = + dyn_cast(ConvertType(ILE->getType())); + + if (!CType) { + // We have a scalar in braces. Just use the first element. + return Visit(ILE->getInit(0)); + } + + if (const llvm::ArrayType *AType = dyn_cast(CType)) + return EmitArrayInitialization(ILE, AType); + + if (const llvm::StructType *SType = dyn_cast(CType)) + return EmitStructInitialization(ILE, SType); + + if (const llvm::VectorType *VType = dyn_cast(CType)) + return EmitVectorInitialization(ILE, VType); + + // Make sure we have an array at this point + assert(0 && "Unable to handle InitListExpr"); + // Get rid of control reaches end of void function warning. + // Not reached. + return 0; + } + + llvm::Constant *VisitImplicitCastExpr(ImplicitCastExpr *ICExpr) { + Expr* SExpr = ICExpr->getSubExpr(); + QualType SType = SExpr->getType(); + llvm::Constant *C; // the intermediate expression + QualType T; // the type of the intermediate expression + if (SType->isArrayType()) { + // Arrays decay to a pointer to the first element + // VLAs would require special handling, but they can't occur here + C = EmitLValue(SExpr); + llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *Ops[] = {Idx0, Idx0}; + C = llvm::ConstantExpr::getGetElementPtr(C, Ops, 2); + + QualType ElemType = SType->getAsArrayType()->getElementType(); + T = CGM.getContext().getPointerType(ElemType); + } else if (SType->isFunctionType()) { + // Function types decay to a pointer to the function + C = EmitLValue(SExpr); + T = CGM.getContext().getPointerType(SType); + } else { + C = Visit(SExpr); + T = SType; + } + + // Perform the conversion; note that an implicit cast can both promote + // and convert an array/function + return EmitConversion(C, T, ICExpr->getType()); + } + + llvm::Constant *VisitStringLiteral(StringLiteral *E) { + const char *StrData = E->getStrData(); + unsigned Len = E->getByteLength(); + assert(!E->getType()->isPointerType() && "Strings are always arrays"); + + // Otherwise this must be a string initializing an array in a static + // initializer. Don't emit it as the address of the string, emit the string + // data itself as an inline array. + const ConstantArrayType *CAT = E->getType()->getAsConstantArrayType(); + assert(CAT && "String isn't pointer or array!"); + + std::string Str(StrData, StrData + Len); + // Null terminate the string before potentially truncating it. + // FIXME: What about wchar_t strings? + Str.push_back(0); + + uint64_t RealLen = CAT->getSize().getZExtValue(); + // String or grow the initializer to the required size. + if (RealLen != Str.size()) + Str.resize(RealLen); + + return llvm::ConstantArray::get(Str, false); + } + + llvm::Constant *VisitDeclRefExpr(DeclRefExpr *E) { + const ValueDecl *Decl = E->getDecl(); + if (const EnumConstantDecl *EC = dyn_cast(Decl)) + return llvm::ConstantInt::get(EC->getInitVal()); + assert(0 && "Unsupported decl ref type!"); + return 0; + } + + llvm::Constant *VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) { + return EmitSizeAlignOf(E->getArgumentType(), E->getType(), E->isSizeOf()); + } + + // Unary operators + llvm::Constant *VisitUnaryPlus(const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + llvm::Constant *VisitUnaryMinus(const UnaryOperator *E) { + return llvm::ConstantExpr::getNeg(Visit(E->getSubExpr())); + } + llvm::Constant *VisitUnaryNot(const UnaryOperator *E) { + return llvm::ConstantExpr::getNot(Visit(E->getSubExpr())); + } + llvm::Constant *VisitUnaryLNot(const UnaryOperator *E) { + llvm::Constant *SubExpr = Visit(E->getSubExpr()); + + if (E->getSubExpr()->getType()->isRealFloatingType()) { + // Compare against 0.0 for fp scalars. + llvm::Constant *Zero = llvm::Constant::getNullValue(SubExpr->getType()); + SubExpr = llvm::ConstantExpr::getFCmp(llvm::FCmpInst::FCMP_UEQ, SubExpr, + Zero); + } else { + assert((E->getSubExpr()->getType()->isIntegerType() || + E->getSubExpr()->getType()->isPointerType()) && + "Unknown scalar type to convert"); + // Compare against an integer or pointer null. + llvm::Constant *Zero = llvm::Constant::getNullValue(SubExpr->getType()); + SubExpr = llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_EQ, SubExpr, + Zero); + } + + return llvm::ConstantExpr::getZExt(SubExpr, ConvertType(E->getType())); + } + llvm::Constant *VisitUnarySizeOf(const UnaryOperator *E) { + return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), true); + } + llvm::Constant *VisitUnaryAlignOf(const UnaryOperator *E) { + return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), false); + } + llvm::Constant *VisitUnaryAddrOf(const UnaryOperator *E) { + return EmitLValue(E->getSubExpr()); + } + llvm::Constant *VisitUnaryOffsetOf(const UnaryOperator *E) { + int64_t Val = E->evaluateOffsetOf(CGM.getContext()); + + assert(E->getType()->isIntegerType() && "Result type must be an integer!"); + + uint32_t ResultWidth = + static_cast(CGM.getContext().getTypeSize(E->getType())); + return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); + } + + // Binary operators + llvm::Constant *VisitBinOr(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + return llvm::ConstantExpr::getOr(LHS, RHS); + } + llvm::Constant *VisitBinSub(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + if (!isa(RHS->getType())) { + // pointer - int + if (isa(LHS->getType())) { + llvm::Constant *Idx = llvm::ConstantExpr::getNeg(RHS); + + return llvm::ConstantExpr::getGetElementPtr(LHS, &Idx, 1); + } + + // int - int + return llvm::ConstantExpr::getSub(LHS, RHS); + } + + assert(0 && "Unhandled bin sub case!"); + return 0; + } + + llvm::Constant *VisitBinShl(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + // LLVM requires the LHS and RHS to be the same type: promote or truncate the + // RHS to the same size as the LHS. + if (LHS->getType() != RHS->getType()) + RHS = llvm::ConstantExpr::getIntegerCast(RHS, LHS->getType(), false); + + return llvm::ConstantExpr::getShl(LHS, RHS); + } + + llvm::Constant *VisitBinMul(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + return llvm::ConstantExpr::getMul(LHS, RHS); + } + + llvm::Constant *VisitBinDiv(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + if (LHS->getType()->isFPOrFPVector()) + return llvm::ConstantExpr::getFDiv(LHS, RHS); + else if (E->getType()->isUnsignedIntegerType()) + return llvm::ConstantExpr::getUDiv(LHS, RHS); + else + return llvm::ConstantExpr::getSDiv(LHS, RHS); + } + + llvm::Constant *VisitBinAdd(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + if (!E->getType()->isPointerType()) + return llvm::ConstantExpr::getAdd(LHS, RHS); + + llvm::Constant *Ptr, *Idx; + if (isa(LHS->getType())) { // pointer + int + Ptr = LHS; + Idx = RHS; + } else { // int + pointer + Ptr = RHS; + Idx = LHS; + } + + return llvm::ConstantExpr::getGetElementPtr(Ptr, &Idx, 1); + } + + llvm::Constant *VisitBinAnd(const BinaryOperator *E) { + llvm::Constant *LHS = Visit(E->getLHS()); + llvm::Constant *RHS = Visit(E->getRHS()); + + return llvm::ConstantExpr::getAnd(LHS, RHS); + } + + // Utility methods + const llvm::Type *ConvertType(QualType T) { + return CGM.getTypes().ConvertType(T); + } + + llvm::Constant *EmitConversionToBool(llvm::Constant *Src, QualType SrcType) { + assert(SrcType->isCanonical() && "EmitConversion strips typedefs"); + + if (SrcType->isRealFloatingType()) { + // Compare against 0.0 for fp scalars. + llvm::Constant *Zero = llvm::Constant::getNullValue(Src->getType()); + return llvm::ConstantExpr::getFCmp(llvm::FCmpInst::FCMP_UNE, Src, Zero); + } + + assert((SrcType->isIntegerType() || SrcType->isPointerType()) && + "Unknown scalar type to convert"); + + // Compare against an integer or pointer null. + llvm::Constant *Zero = llvm::Constant::getNullValue(Src->getType()); + return llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_NE, Src, Zero); + } + + llvm::Constant *EmitConversion(llvm::Constant *Src, QualType SrcType, + QualType DstType) { + SrcType = SrcType.getCanonicalType(); + DstType = DstType.getCanonicalType(); + if (SrcType == DstType) return Src; + + // Handle conversions to bool first, they are special: comparisons against 0. + if (DstType->isBooleanType()) + return EmitConversionToBool(Src, SrcType); + + const llvm::Type *DstTy = ConvertType(DstType); + + // Ignore conversions like int -> uint. + if (Src->getType() == DstTy) + return Src; + + // Handle pointer conversions next: pointers can only be converted to/from + // other pointers and integers. + if (isa(DstType)) { + // The source value may be an integer, or a pointer. + if (isa(Src->getType())) + return llvm::ConstantExpr::getBitCast(Src, DstTy); + assert(SrcType->isIntegerType() &&"Not ptr->ptr or int->ptr conversion?"); + return llvm::ConstantExpr::getIntToPtr(Src, DstTy); + } + + if (isa(SrcType)) { + // Must be an ptr to int cast. + assert(isa(DstTy) && "not ptr->int?"); + return llvm::ConstantExpr::getPtrToInt(Src, DstTy); + } + + // A scalar source can be splatted to a vector of the same element type + if (isa(DstTy) && !isa(SrcType)) { + const llvm::VectorType *VT = cast(DstTy); + assert((VT->getElementType() == Src->getType()) && + "Vector element type must match scalar type to splat."); + unsigned NumElements = DstType->getAsVectorType()->getNumElements(); + llvm::SmallVector Elements; + for (unsigned i = 0; i < NumElements; i++) + Elements.push_back(Src); + + return llvm::ConstantVector::get(&Elements[0], NumElements); + } + + if (isa(Src->getType()) || + isa(DstTy)) { + return llvm::ConstantExpr::getBitCast(Src, DstTy); + } + + // Finally, we have the arithmetic types: real int/float. + if (isa(Src->getType())) { + bool InputSigned = SrcType->isSignedIntegerType(); + if (isa(DstTy)) + return llvm::ConstantExpr::getIntegerCast(Src, DstTy, InputSigned); + else if (InputSigned) + return llvm::ConstantExpr::getSIToFP(Src, DstTy); + else + return llvm::ConstantExpr::getUIToFP(Src, DstTy); + } + + assert(Src->getType()->isFloatingPoint() && "Unknown real conversion"); + if (isa(DstTy)) { + if (DstType->isSignedIntegerType()) + return llvm::ConstantExpr::getFPToSI(Src, DstTy); + else + return llvm::ConstantExpr::getFPToUI(Src, DstTy); + } + + assert(DstTy->isFloatingPoint() && "Unknown real conversion"); + if (DstTy->getTypeID() < Src->getType()->getTypeID()) + return llvm::ConstantExpr::getFPTrunc(Src, DstTy); + else + return llvm::ConstantExpr::getFPExtend(Src, DstTy); + } + + llvm::Constant *EmitSizeAlignOf(QualType TypeToSize, + QualType RetType, bool isSizeOf) { + std::pair Info = + CGM.getContext().getTypeInfo(TypeToSize); + + uint64_t Val = isSizeOf ? Info.first : Info.second; + Val /= 8; // Return size in bytes, not bits. + + assert(RetType->isIntegerType() && "Result type must be an integer!"); + + uint32_t ResultWidth = + static_cast(CGM.getContext().getTypeSize(RetType)); + return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); + } + + llvm::Constant *EmitLValue(Expr *E) { + switch (E->getStmtClass()) { + default: break; + case Expr::ParenExprClass: + // Elide parenthesis + return EmitLValue(cast(E)->getSubExpr()); + case Expr::CompoundLiteralExprClass: { + // Note that due to the nature of compound literals, this is guaranteed + // to be the only use of the variable, so we just generate it here. + CompoundLiteralExpr *CLE = cast(E); + llvm::Constant* C = Visit(CLE->getInitializer()); + C = new llvm::GlobalVariable(C->getType(),E->getType().isConstQualified(), + llvm::GlobalValue::InternalLinkage, + C, ".compoundliteral", &CGM.getModule()); + return C; + } + case Expr::DeclRefExprClass: { + ValueDecl *Decl = cast(E)->getDecl(); + if (const FunctionDecl *FD = dyn_cast(Decl)) + return CGM.GetAddrOfFunctionDecl(FD, false); + if (const FileVarDecl* VD = dyn_cast(Decl)) + return CGM.GetAddrOfGlobalVar(VD, false); + if (const BlockVarDecl* BVD = dyn_cast(Decl)) { + assert(CGF && "Can't access static local vars without CGF"); + return CGF->GetAddrOfStaticLocalVar(BVD); + } + break; + } + case Expr::MemberExprClass: { + MemberExpr* ME = cast(E); + llvm::Constant *Base; + if (ME->isArrow()) + Base = Visit(ME->getBase()); + else + Base = EmitLValue(ME->getBase()); + + unsigned FieldNumber = CGM.getTypes().getLLVMFieldNo(ME->getMemberDecl()); + llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, + FieldNumber); + llvm::Value *Ops[] = {Zero, Idx}; + return llvm::ConstantExpr::getGetElementPtr(Base, Ops, 2); + } + case Expr::ArraySubscriptExprClass: { + ArraySubscriptExpr* ASExpr = cast(E); + llvm::Constant *Base = Visit(ASExpr->getBase()); + llvm::Constant *Index = Visit(ASExpr->getIdx()); + assert(!ASExpr->getBase()->getType()->isVectorType() && + "Taking the address of a vector component is illegal!"); + return llvm::ConstantExpr::getGetElementPtr(Base, &Index, 1); + } + case Expr::StringLiteralClass: { + StringLiteral *String = cast(E); + assert(!String->isWide() && "Cannot codegen wide strings yet"); + const char *StrData = String->getStrData(); + unsigned Len = String->getByteLength(); + + return CGM.GetAddrOfConstantString(std::string(StrData, StrData + Len)); + } + case Expr::UnaryOperatorClass: { + UnaryOperator *Exp = cast(E); + switch (Exp->getOpcode()) { + default: break; + case UnaryOperator::Extension: + // Extension is just a wrapper for expressions + return EmitLValue(Exp->getSubExpr()); + case UnaryOperator::Real: + case UnaryOperator::Imag: { + // The address of __real or __imag is just a GEP off the address + // of the internal expression + llvm::Constant* C = EmitLValue(Exp->getSubExpr()); + llvm::Constant *Zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, + Exp->getOpcode() == UnaryOperator::Imag); + llvm::Value *Ops[] = {Zero, Idx}; + return llvm::ConstantExpr::getGetElementPtr(C, Ops, 2); + } + case UnaryOperator::Deref: + // The address of a deref is just the value of the expression + return Visit(Exp->getSubExpr()); + } + break; + } + } + CGM.WarnUnsupported(E, "constant l-value expression"); + llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); + return llvm::UndefValue::get(Ty); + } + +}; + +} // end anonymous namespace. + + +llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, + CodeGenFunction *CGF) +{ + QualType type = E->getType().getCanonicalType(); + + if (type->isIntegerType()) { + llvm::APSInt Value(static_cast(Context.getTypeSize(type))); + if (E->isIntegerConstantExpr(Value, Context)) { + return llvm::ConstantInt::get(Value); + } + } + + return ConstExprEmitter(*this, CGF).Visit(const_cast(E)); +} diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp new file mode 100644 index 00000000000..892712a0d4c --- /dev/null +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -0,0 +1,1185 @@ +//===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Expr nodes with scalar LLVM types as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/AST.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/Compiler.h" +#include + +using namespace clang; +using namespace CodeGen; +using llvm::Value; + +//===----------------------------------------------------------------------===// +// Scalar Expression Emitter +//===----------------------------------------------------------------------===// + +struct BinOpInfo { + Value *LHS; + Value *RHS; + QualType Ty; // Computation Type. + const BinaryOperator *E; +}; + +namespace { +class VISIBILITY_HIDDEN ScalarExprEmitter + : public StmtVisitor { + CodeGenFunction &CGF; + llvm::LLVMFoldingBuilder &Builder; + CGObjCRuntime *Runtime; + + +public: + + ScalarExprEmitter(CodeGenFunction &cgf) : CGF(cgf), + Builder(CGF.Builder), + Runtime(CGF.CGM.getObjCRuntime()) { + } + + + //===--------------------------------------------------------------------===// + // Utilities + //===--------------------------------------------------------------------===// + + const llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } + LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } + + Value *EmitLoadOfLValue(LValue LV, QualType T) { + return CGF.EmitLoadOfLValue(LV, T).getScalarVal(); + } + + /// EmitLoadOfLValue - Given an expression with complex type that represents a + /// value l-value, this method emits the address of the l-value, then loads + /// and returns the result. + Value *EmitLoadOfLValue(const Expr *E) { + // FIXME: Volatile + return EmitLoadOfLValue(EmitLValue(E), E->getType()); + } + + /// EmitConversionToBool - Convert the specified expression value to a + /// boolean (i1) truth value. This is equivalent to "Val != 0". + Value *EmitConversionToBool(Value *Src, QualType DstTy); + + /// EmitScalarConversion - Emit a conversion from the specified type to the + /// specified destination type, both of which are LLVM scalar types. + Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy); + + /// EmitComplexToScalarConversion - Emit a conversion from the specified + /// complex type to the specified destination type, where the destination + /// type is an LLVM scalar type. + Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, + QualType SrcTy, QualType DstTy); + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + Value *VisitStmt(Stmt *S) { + S->dump(CGF.getContext().getSourceManager()); + assert(0 && "Stmt can't have complex result type!"); + return 0; + } + Value *VisitExpr(Expr *S); + Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); } + + // Leaves. + Value *VisitIntegerLiteral(const IntegerLiteral *E) { + return llvm::ConstantInt::get(E->getValue()); + } + Value *VisitFloatingLiteral(const FloatingLiteral *E) { + return llvm::ConstantFP::get(ConvertType(E->getType()), E->getValue()); + } + Value *VisitCharacterLiteral(const CharacterLiteral *E) { + return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); + } + Value *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { + return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); + } + Value *VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) { + return llvm::ConstantInt::get(ConvertType(E->getType()), + CGF.getContext().typesAreCompatible( + E->getArgType1(), E->getArgType2())); + } + Value *VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) { + return EmitSizeAlignOf(E->getArgumentType(), E->getType(), E->isSizeOf()); + } + + // l-values. + Value *VisitDeclRefExpr(DeclRefExpr *E) { + if (const EnumConstantDecl *EC = dyn_cast(E->getDecl())) + return llvm::ConstantInt::get(EC->getInitVal()); + return EmitLoadOfLValue(E); + } + Value *VisitObjCMessageExpr(ObjCMessageExpr *E); + Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); + Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitOCUVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); } + Value *VisitPreDefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } + + Value *VisitInitListExpr(InitListExpr *E) { + unsigned NumInitElements = E->getNumInits(); + + const llvm::VectorType *VType = + dyn_cast(ConvertType(E->getType())); + + // We have a scalar in braces. Just use the first element. + if (!VType) + return Visit(E->getInit(0)); + + unsigned NumVectorElements = VType->getNumElements(); + const llvm::Type *ElementType = VType->getElementType(); + + // Emit individual vector element stores. + llvm::Value *V = llvm::UndefValue::get(VType); + + // Emit initializers + unsigned i; + for (i = 0; i < NumInitElements; ++i) { + Value *NewV = Visit(E->getInit(i)); + Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + V = Builder.CreateInsertElement(V, NewV, Idx); + } + + // Emit remaining default initializers + for (/* Do not initialize i*/; i < NumVectorElements; ++i) { + Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + llvm::Value *NewV = llvm::Constant::getNullValue(ElementType); + V = Builder.CreateInsertElement(V, NewV, Idx); + } + + return V; + } + + Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + return Visit(E->getInitializer()); + } + + Value *VisitImplicitCastExpr(const ImplicitCastExpr *E); + Value *VisitCastExpr(const CastExpr *E) { + return EmitCastExpr(E->getSubExpr(), E->getType()); + } + Value *EmitCastExpr(const Expr *E, QualType T); + + Value *VisitCallExpr(const CallExpr *E) { + return CGF.EmitCallExpr(E).getScalarVal(); + } + + Value *VisitStmtExpr(const StmtExpr *E); + + // Unary Operators. + Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre); + Value *VisitUnaryPostDec(const UnaryOperator *E) { + return VisitPrePostIncDec(E, false, false); + } + Value *VisitUnaryPostInc(const UnaryOperator *E) { + return VisitPrePostIncDec(E, true, false); + } + Value *VisitUnaryPreDec(const UnaryOperator *E) { + return VisitPrePostIncDec(E, false, true); + } + Value *VisitUnaryPreInc(const UnaryOperator *E) { + return VisitPrePostIncDec(E, true, true); + } + Value *VisitUnaryAddrOf(const UnaryOperator *E) { + return EmitLValue(E->getSubExpr()).getAddress(); + } + Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitUnaryPlus(const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + Value *VisitUnaryMinus (const UnaryOperator *E); + Value *VisitUnaryNot (const UnaryOperator *E); + Value *VisitUnaryLNot (const UnaryOperator *E); + Value *VisitUnarySizeOf (const UnaryOperator *E) { + return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), true); + } + Value *VisitUnaryAlignOf (const UnaryOperator *E) { + return EmitSizeAlignOf(E->getSubExpr()->getType(), E->getType(), false); + } + Value *EmitSizeAlignOf(QualType TypeToSize, QualType RetType, + bool isSizeOf); + Value *VisitUnaryReal (const UnaryOperator *E); + Value *VisitUnaryImag (const UnaryOperator *E); + Value *VisitUnaryExtension(const UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + Value *VisitUnaryOffsetOf(const UnaryOperator *E); + + // Binary Operators. + Value *EmitMul(const BinOpInfo &Ops) { + return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); + } + Value *EmitDiv(const BinOpInfo &Ops); + Value *EmitRem(const BinOpInfo &Ops); + Value *EmitAdd(const BinOpInfo &Ops); + Value *EmitSub(const BinOpInfo &Ops); + Value *EmitShl(const BinOpInfo &Ops); + Value *EmitShr(const BinOpInfo &Ops); + Value *EmitAnd(const BinOpInfo &Ops) { + return Builder.CreateAnd(Ops.LHS, Ops.RHS, "and"); + } + Value *EmitXor(const BinOpInfo &Ops) { + return Builder.CreateXor(Ops.LHS, Ops.RHS, "xor"); + } + Value *EmitOr (const BinOpInfo &Ops) { + return Builder.CreateOr(Ops.LHS, Ops.RHS, "or"); + } + + BinOpInfo EmitBinOps(const BinaryOperator *E); + Value *EmitCompoundAssign(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*F)(const BinOpInfo &)); + + // Binary operators and binary compound assignment operators. +#define HANDLEBINOP(OP) \ + Value *VisitBin ## OP(const BinaryOperator *E) { \ + return Emit ## OP(EmitBinOps(E)); \ + } \ + Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \ + return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \ + } + HANDLEBINOP(Mul); + HANDLEBINOP(Div); + HANDLEBINOP(Rem); + HANDLEBINOP(Add); + // (Sub) - Sub is handled specially below for ptr-ptr subtract. + HANDLEBINOP(Shl); + HANDLEBINOP(Shr); + HANDLEBINOP(And); + HANDLEBINOP(Xor); + HANDLEBINOP(Or); +#undef HANDLEBINOP + Value *VisitBinSub(const BinaryOperator *E); + Value *VisitBinSubAssign(const CompoundAssignOperator *E) { + return EmitCompoundAssign(E, &ScalarExprEmitter::EmitSub); + } + + // Comparisons. + Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc, + unsigned SICmpOpc, unsigned FCmpOpc); +#define VISITCOMP(CODE, UI, SI, FP) \ + Value *VisitBin##CODE(const BinaryOperator *E) { \ + return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \ + llvm::FCmpInst::FP); } + VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT); + VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT); + VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE); + VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE); + VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ); + VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE); +#undef VISITCOMP + + Value *VisitBinAssign (const BinaryOperator *E); + + Value *VisitBinLAnd (const BinaryOperator *E); + Value *VisitBinLOr (const BinaryOperator *E); + Value *VisitBinComma (const BinaryOperator *E); + + // Other Operators. + Value *VisitConditionalOperator(const ConditionalOperator *CO); + Value *VisitChooseExpr(ChooseExpr *CE); + Value *VisitOverloadExpr(OverloadExpr *OE); + Value *VisitVAArgExpr(VAArgExpr *VE); + Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { + return CGF.EmitObjCStringLiteral(E); + } + Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E); +}; +} // end anonymous namespace. + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +/// EmitConversionToBool - Convert the specified expression value to a +/// boolean (i1) truth value. This is equivalent to "Val != 0". +Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { + assert(SrcType->isCanonical() && "EmitScalarConversion strips typedefs"); + + if (SrcType->isRealFloatingType()) { + // Compare against 0.0 for fp scalars. + llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType()); + return Builder.CreateFCmpUNE(Src, Zero, "tobool"); + } + + assert((SrcType->isIntegerType() || SrcType->isPointerType()) && + "Unknown scalar type to convert"); + + // Because of the type rules of C, we often end up computing a logical value, + // then zero extending it to int, then wanting it as a logical value again. + // Optimize this common case. + if (llvm::ZExtInst *ZI = dyn_cast(Src)) { + if (ZI->getOperand(0)->getType() == llvm::Type::Int1Ty) { + Value *Result = ZI->getOperand(0); + // If there aren't any more uses, zap the instruction to save space. + // Note that there can be more uses, for example if this + // is the result of an assignment. + if (ZI->use_empty()) + ZI->eraseFromParent(); + return Result; + } + } + + // Compare against an integer or pointer null. + llvm::Value *Zero = llvm::Constant::getNullValue(Src->getType()); + return Builder.CreateICmpNE(Src, Zero, "tobool"); +} + +/// EmitScalarConversion - Emit a conversion from the specified type to the +/// specified destination type, both of which are LLVM scalar types. +Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, + QualType DstType) { + SrcType = SrcType.getCanonicalType(); + DstType = DstType.getCanonicalType(); + if (SrcType == DstType) return Src; + + if (DstType->isVoidType()) return 0; + + // Handle conversions to bool first, they are special: comparisons against 0. + if (DstType->isBooleanType()) + return EmitConversionToBool(Src, SrcType); + + const llvm::Type *DstTy = ConvertType(DstType); + + // Ignore conversions like int -> uint. + if (Src->getType() == DstTy) + return Src; + + // Handle pointer conversions next: pointers can only be converted to/from + // other pointers and integers. + if (isa(DstType)) { + // The source value may be an integer, or a pointer. + if (isa(Src->getType())) + return Builder.CreateBitCast(Src, DstTy, "conv"); + assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); + return Builder.CreateIntToPtr(Src, DstTy, "conv"); + } + + if (isa(SrcType)) { + // Must be an ptr to int cast. + assert(isa(DstTy) && "not ptr->int?"); + return Builder.CreatePtrToInt(Src, DstTy, "conv"); + } + + // A scalar source can be splatted to an OCU vector of the same element type + if (DstType->isOCUVectorType() && !isa(SrcType) && + cast(DstTy)->getElementType() == Src->getType()) + return CGF.EmitVector(&Src, DstType->getAsVectorType()->getNumElements(), + true); + + // Allow bitcast from vector to integer/fp of the same size. + if (isa(Src->getType()) || + isa(DstTy)) + return Builder.CreateBitCast(Src, DstTy, "conv"); + + // Finally, we have the arithmetic types: real int/float. + if (isa(Src->getType())) { + bool InputSigned = SrcType->isSignedIntegerType(); + if (isa(DstTy)) + return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); + else if (InputSigned) + return Builder.CreateSIToFP(Src, DstTy, "conv"); + else + return Builder.CreateUIToFP(Src, DstTy, "conv"); + } + + assert(Src->getType()->isFloatingPoint() && "Unknown real conversion"); + if (isa(DstTy)) { + if (DstType->isSignedIntegerType()) + return Builder.CreateFPToSI(Src, DstTy, "conv"); + else + return Builder.CreateFPToUI(Src, DstTy, "conv"); + } + + assert(DstTy->isFloatingPoint() && "Unknown real conversion"); + if (DstTy->getTypeID() < Src->getType()->getTypeID()) + return Builder.CreateFPTrunc(Src, DstTy, "conv"); + else + return Builder.CreateFPExt(Src, DstTy, "conv"); +} + +/// EmitComplexToScalarConversion - Emit a conversion from the specified +/// complex type to the specified destination type, where the destination +/// type is an LLVM scalar type. +Value *ScalarExprEmitter:: +EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, + QualType SrcTy, QualType DstTy) { + // Get the source element type. + SrcTy = cast(SrcTy.getCanonicalType())->getElementType(); + + // Handle conversions to bool first, they are special: comparisons against 0. + if (DstTy->isBooleanType()) { + // Complex != 0 -> (Real != 0) | (Imag != 0) + Src.first = EmitScalarConversion(Src.first, SrcTy, DstTy); + Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy); + return Builder.CreateOr(Src.first, Src.second, "tobool"); + } + + // C99 6.3.1.7p2: "When a value of complex type is converted to a real type, + // the imaginary part of the complex value is discarded and the value of the + // real part is converted according to the conversion rules for the + // corresponding real type. + return EmitScalarConversion(Src.first, SrcTy, DstTy); +} + + +//===----------------------------------------------------------------------===// +// Visitor Methods +//===----------------------------------------------------------------------===// + +Value *ScalarExprEmitter::VisitExpr(Expr *E) { + CGF.WarnUnsupported(E, "scalar expression"); + if (E->getType()->isVoidType()) + return 0; + return llvm::UndefValue::get(CGF.ConvertType(E->getType())); +} + +Value *ScalarExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { + // Only the lookup mechanism and first two arguments of the method + // implementation vary between runtimes. We can get the receiver and + // arguments in generic code. + + // Find the receiver + llvm::Value * Receiver = CGF.EmitScalarExpr(E->getReceiver()); + + // Process the arguments + unsigned int ArgC = E->getNumArgs(); + llvm::SmallVector Args; + for(unsigned i=0 ; igetArg(i); + QualType ArgTy = ArgExpr->getType(); + if (!CGF.hasAggregateLLVMType(ArgTy)) { + // Scalar argument is passed by-value. + Args.push_back(CGF.EmitScalarExpr(ArgExpr)); + } else if (ArgTy->isComplexType()) { + // Make a temporary alloca to pass the argument. + llvm::Value *DestMem = CGF.CreateTempAlloca(ConvertType(ArgTy)); + CGF.EmitComplexExprIntoAddr(ArgExpr, DestMem, false); + Args.push_back(DestMem); + } else { + llvm::Value *DestMem = CGF.CreateTempAlloca(ConvertType(ArgTy)); + CGF.EmitAggExpr(ArgExpr, DestMem, false); + Args.push_back(DestMem); + } + } + + // Get the selector string + std::string SelStr = E->getSelector().getName(); + llvm::Constant *Selector = CGF.CGM.GetAddrOfConstantString(SelStr); + ConvertType(E->getType()); + return Runtime->generateMessageSend(Builder, + ConvertType(E->getType()), + Receiver, + Selector, + &Args[0], + Args.size()); +} + +Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + // Emit subscript expressions in rvalue context's. For most cases, this just + // loads the lvalue formed by the subscript expr. However, we have to be + // careful, because the base of a vector subscript is occasionally an rvalue, + // so we can't get it as an lvalue. + if (!E->getBase()->getType()->isVectorType()) + return EmitLoadOfLValue(E); + + // Handle the vector case. The base must be a vector, the index must be an + // integer value. + Value *Base = Visit(E->getBase()); + Value *Idx = Visit(E->getIdx()); + + // FIXME: Convert Idx to i32 type. + return Builder.CreateExtractElement(Base, Idx, "vecext"); +} + +/// VisitImplicitCastExpr - Implicit casts are the same as normal casts, but +/// also handle things like function to pointer-to-function decay, and array to +/// pointer decay. +Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) { + const Expr *Op = E->getSubExpr(); + + // If this is due to array->pointer conversion, emit the array expression as + // an l-value. + if (Op->getType()->isArrayType()) { + // FIXME: For now we assume that all source arrays map to LLVM arrays. This + // will not true when we add support for VLAs. + Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays. + + assert(isa(V->getType()) && + isa(cast(V->getType()) + ->getElementType()) && + "Doesn't support VLAs yet!"); + llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + + llvm::Value *Ops[] = {Idx0, Idx0}; + V = Builder.CreateGEP(V, Ops, Ops+2, "arraydecay"); + + // The resultant pointer type can be implicitly casted to other pointer + // types as well, for example void*. + const llvm::Type *DestPTy = ConvertType(E->getType()); + assert(isa(DestPTy) && + "Only expect implicit cast to pointer"); + if (V->getType() != DestPTy) + V = Builder.CreateBitCast(V, DestPTy, "ptrconv"); + return V; + + } else if (E->getType()->isReferenceType()) { + assert(cast(E->getType().getCanonicalType())-> + getReferenceeType() == + Op->getType().getCanonicalType() && "Incompatible types!"); + + return EmitLValue(Op).getAddress(); + } + + return EmitCastExpr(Op, E->getType()); +} + + +// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts +// have to handle a more broad range of conversions than explicit casts, as they +// handle things like function to ptr-to-function decay etc. +Value *ScalarExprEmitter::EmitCastExpr(const Expr *E, QualType DestTy) { + // Handle cases where the source is an non-complex type. + + if (!CGF.hasAggregateLLVMType(E->getType())) { + Value *Src = Visit(const_cast(E)); + + // Use EmitScalarConversion to perform the conversion. + return EmitScalarConversion(Src, E->getType(), DestTy); + } + + if (E->getType()->isComplexType()) { + // Handle cases where the source is a complex type. + return EmitComplexToScalarConversion(CGF.EmitComplexExpr(E), E->getType(), + DestTy); + } + + // Okay, this is a cast from an aggregate. It must be a cast to void. Just + // evaluate the result and return. + CGF.EmitAggExpr(E, 0, false); + return 0; +} + +Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { + return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getScalarVal(); +} + + +//===----------------------------------------------------------------------===// +// Unary Operators +//===----------------------------------------------------------------------===// + +Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, + bool isInc, bool isPre) { + LValue LV = EmitLValue(E->getSubExpr()); + // FIXME: Handle volatile! + Value *InVal = CGF.EmitLoadOfLValue(LV, // false + E->getSubExpr()->getType()).getScalarVal(); + + int AmountVal = isInc ? 1 : -1; + + Value *NextVal; + if (isa(InVal->getType())) { + // FIXME: This isn't right for VLAs. + NextVal = llvm::ConstantInt::get(llvm::Type::Int32Ty, AmountVal); + NextVal = Builder.CreateGEP(InVal, NextVal); + } else { + // Add the inc/dec to the real part. + if (isa(InVal->getType())) + NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); + else if (InVal->getType() == llvm::Type::FloatTy) + // FIXME: Handle long double. + NextVal = + llvm::ConstantFP::get(InVal->getType(), + llvm::APFloat(static_cast(AmountVal))); + else { + // FIXME: Handle long double. + assert(InVal->getType() == llvm::Type::DoubleTy); + NextVal = + llvm::ConstantFP::get(InVal->getType(), + llvm::APFloat(static_cast(AmountVal))); + } + NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + } + + // Store the updated result through the lvalue. + CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, + E->getSubExpr()->getType()); + + // If this is a postinc, return the value read from memory, otherwise use the + // updated value. + return isPre ? NextVal : InVal; +} + + +Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { + Value *Op = Visit(E->getSubExpr()); + return Builder.CreateNeg(Op, "neg"); +} + +Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) { + Value *Op = Visit(E->getSubExpr()); + return Builder.CreateNot(Op, "neg"); +} + +Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { + // Compare operand to zero. + Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr()); + + // Invert value. + // TODO: Could dynamically modify easy computations here. For example, if + // the operand is an icmp ne, turn into icmp eq. + BoolVal = Builder.CreateNot(BoolVal, "lnot"); + + // ZExt result to int. + return Builder.CreateZExt(BoolVal, CGF.LLVMIntTy, "lnot.ext"); +} + +/// EmitSizeAlignOf - Return the size or alignment of the 'TypeToSize' type as +/// an integer (RetType). +Value *ScalarExprEmitter::EmitSizeAlignOf(QualType TypeToSize, + QualType RetType,bool isSizeOf){ + assert(RetType->isIntegerType() && "Result type must be an integer!"); + uint32_t ResultWidth = + static_cast(CGF.getContext().getTypeSize(RetType)); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (TypeToSize->isVoidType()) + return llvm::ConstantInt::get(llvm::APInt(ResultWidth, 1)); + + /// FIXME: This doesn't handle VLAs yet! + std::pair Info = CGF.getContext().getTypeInfo(TypeToSize); + + uint64_t Val = isSizeOf ? Info.first : Info.second; + Val /= 8; // Return size in bytes, not bits. + + return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); +} + +Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) { + Expr *Op = E->getSubExpr(); + if (Op->getType()->isComplexType()) + return CGF.EmitComplexExpr(Op).first; + return Visit(Op); +} +Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { + Expr *Op = E->getSubExpr(); + if (Op->getType()->isComplexType()) + return CGF.EmitComplexExpr(Op).second; + + // __imag on a scalar returns zero. Emit it the subexpr to ensure side + // effects are evaluated. + CGF.EmitScalarExpr(Op); + return llvm::Constant::getNullValue(ConvertType(E->getType())); +} + +Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) +{ + int64_t Val = E->evaluateOffsetOf(CGF.getContext()); + + assert(E->getType()->isIntegerType() && "Result type must be an integer!"); + + uint32_t ResultWidth = + static_cast(CGF.getContext().getTypeSize(E->getType())); + return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); +} + +//===----------------------------------------------------------------------===// +// Binary Operators +//===----------------------------------------------------------------------===// + +BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { + BinOpInfo Result; + Result.LHS = Visit(E->getLHS()); + Result.RHS = Visit(E->getRHS()); + Result.Ty = E->getType(); + Result.E = E; + return Result; +} + +Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { + QualType LHSTy = E->getLHS()->getType(), RHSTy = E->getRHS()->getType(); + + BinOpInfo OpInfo; + + // Load the LHS and RHS operands. + LValue LHSLV = EmitLValue(E->getLHS()); + OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); + + // Determine the computation type. If the RHS is complex, then this is one of + // the add/sub/mul/div operators. All of these operators can be computed in + // with just their real component even though the computation domain really is + // complex. + QualType ComputeType = E->getComputationType(); + + // If the computation type is complex, then the RHS is complex. Emit the RHS. + if (const ComplexType *CT = ComputeType->getAsComplexType()) { + ComputeType = CT->getElementType(); + + // Emit the RHS, only keeping the real component. + OpInfo.RHS = CGF.EmitComplexExpr(E->getRHS()).first; + RHSTy = RHSTy->getAsComplexType()->getElementType(); + } else { + // Otherwise the RHS is a simple scalar value. + OpInfo.RHS = Visit(E->getRHS()); + } + + // Convert the LHS/RHS values to the computation type. + OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, ComputeType); + + // Do not merge types for -= or += where the LHS is a pointer. + if (!(E->getOpcode() == BinaryOperator::SubAssign || + E->getOpcode() == BinaryOperator::AddAssign) || + !E->getLHS()->getType()->isPointerType()) { + OpInfo.RHS = EmitScalarConversion(OpInfo.RHS, RHSTy, ComputeType); + } + OpInfo.Ty = ComputeType; + OpInfo.E = E; + + // Expand the binary operator. + Value *Result = (this->*Func)(OpInfo); + + // Truncate the result back to the LHS type. + Result = EmitScalarConversion(Result, ComputeType, LHSTy); + + // Store the result value into the LHS lvalue. + CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, E->getType()); + + return Result; +} + + +Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { + if (Ops.LHS->getType()->isFPOrFPVector()) + return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); + else if (Ops.Ty->isUnsignedIntegerType()) + return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div"); + else + return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div"); +} + +Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { + // Rem in C can't be a floating point type: C99 6.5.5p2. + if (Ops.Ty->isUnsignedIntegerType()) + return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); + else + return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); +} + + +Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { + if (!Ops.Ty->isPointerType()) + return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); + + // FIXME: What about a pointer to a VLA? + Value *Ptr, *Idx; + Expr *IdxExp; + if (isa(Ops.LHS->getType())) { // pointer + int + Ptr = Ops.LHS; + Idx = Ops.RHS; + IdxExp = Ops.E->getRHS(); + } else { // int + pointer + Ptr = Ops.RHS; + Idx = Ops.LHS; + IdxExp = Ops.E->getLHS(); + } + + unsigned Width = cast(Idx->getType())->getBitWidth(); + if (Width < CGF.LLVMPointerWidth) { + // Zero or sign extend the pointer value based on whether the index is + // signed or not. + const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth); + if (IdxExp->getType().getCanonicalType()->isSignedIntegerType()) + Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); + else + Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); + } + + return Builder.CreateGEP(Ptr, Idx, "add.ptr"); +} + +Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { + if (!isa(Ops.LHS->getType())) + return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); + + // pointer - int + assert(!isa(Ops.RHS->getType()) && + "ptr-ptr shouldn't get here"); + // FIXME: The pointer could point to a VLA. + Value *Idx = Builder.CreateNeg(Ops.RHS, "sub.ptr.neg"); + + unsigned Width = cast(Idx->getType())->getBitWidth(); + if (Width < CGF.LLVMPointerWidth) { + // Zero or sign extend the pointer value based on whether the index is + // signed or not. + const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth); + if (Ops.E->getRHS()->getType().getCanonicalType()->isSignedIntegerType()) + Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext"); + else + Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); + } + + return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr"); +} + +Value *ScalarExprEmitter::VisitBinSub(const BinaryOperator *E) { + // "X - Y" is different from "X -= Y" in one case: when Y is a pointer. In + // the compound assignment case it is invalid, so just handle it here. + if (!E->getRHS()->getType()->isPointerType()) + return EmitSub(EmitBinOps(E)); + + // pointer - pointer + Value *LHS = Visit(E->getLHS()); + Value *RHS = Visit(E->getRHS()); + + const QualType LHSType = E->getLHS()->getType().getCanonicalType(); + const QualType LHSElementType = cast(LHSType)->getPointeeType(); + uint64_t ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8; + + const llvm::Type *ResultType = ConvertType(E->getType()); + LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast"); + RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); + Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); + + // HACK: LLVM doesn't have an divide instruction that 'knows' there is no + // remainder. As such, we handle common power-of-two cases here to generate + // better code. + if (llvm::isPowerOf2_64(ElementSize)) { + Value *ShAmt = + llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize)); + return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr"); + } + + // Otherwise, do a full sdiv. + Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize); + return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); +} + + +Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { + // LLVM requires the LHS and RHS to be the same type: promote or truncate the + // RHS to the same size as the LHS. + Value *RHS = Ops.RHS; + if (Ops.LHS->getType() != RHS->getType()) + RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + + return Builder.CreateShl(Ops.LHS, RHS, "shl"); +} + +Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { + // LLVM requires the LHS and RHS to be the same type: promote or truncate the + // RHS to the same size as the LHS. + Value *RHS = Ops.RHS; + if (Ops.LHS->getType() != RHS->getType()) + RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + + if (Ops.Ty->isUnsignedIntegerType()) + return Builder.CreateLShr(Ops.LHS, RHS, "shr"); + return Builder.CreateAShr(Ops.LHS, RHS, "shr"); +} + +Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, + unsigned SICmpOpc, unsigned FCmpOpc) { + Value *Result; + QualType LHSTy = E->getLHS()->getType(); + if (!LHSTy->isComplexType()) { + Value *LHS = Visit(E->getLHS()); + Value *RHS = Visit(E->getRHS()); + + if (LHS->getType()->isFloatingPoint()) { + Result = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, + LHS, RHS, "cmp"); + } else if (LHSTy->isUnsignedIntegerType()) { + Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHS, RHS, "cmp"); + } else { + // Signed integers and pointers. + Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc, + LHS, RHS, "cmp"); + } + } else { + // Complex Comparison: can only be an equality comparison. + CodeGenFunction::ComplexPairTy LHS = CGF.EmitComplexExpr(E->getLHS()); + CodeGenFunction::ComplexPairTy RHS = CGF.EmitComplexExpr(E->getRHS()); + + QualType CETy = + cast(LHSTy.getCanonicalType())->getElementType(); + + Value *ResultR, *ResultI; + if (CETy->isRealFloatingType()) { + ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, + LHS.first, RHS.first, "cmp.r"); + ResultI = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, + LHS.second, RHS.second, "cmp.i"); + } else { + // Complex comparisons can only be equality comparisons. As such, signed + // and unsigned opcodes are the same. + ResultR = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHS.first, RHS.first, "cmp.r"); + ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHS.second, RHS.second, "cmp.i"); + } + + if (E->getOpcode() == BinaryOperator::EQ) { + Result = Builder.CreateAnd(ResultR, ResultI, "and.ri"); + } else { + assert(E->getOpcode() == BinaryOperator::NE && + "Complex comparison other than == or != ?"); + Result = Builder.CreateOr(ResultR, ResultI, "or.ri"); + } + } + + // ZExt result to int. + return Builder.CreateZExt(Result, CGF.LLVMIntTy, "cmp.ext"); +} + +Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { + LValue LHS = EmitLValue(E->getLHS()); + Value *RHS = Visit(E->getRHS()); + + // Store the value into the LHS. + // FIXME: Volatility! + CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType()); + + // Return the RHS. + return RHS; +} + +Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { + Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS()); + + llvm::BasicBlock *ContBlock = new llvm::BasicBlock("land_cont"); + llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("land_rhs"); + + llvm::BasicBlock *OrigBlock = Builder.GetInsertBlock(); + Builder.CreateCondBr(LHSCond, RHSBlock, ContBlock); + + CGF.EmitBlock(RHSBlock); + Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); + + // Reaquire the RHS block, as there may be subblocks inserted. + RHSBlock = Builder.GetInsertBlock(); + CGF.EmitBlock(ContBlock); + + // Create a PHI node. If we just evaluted the LHS condition, the result is + // false. If we evaluated both, the result is the RHS condition. + llvm::PHINode *PN = Builder.CreatePHI(llvm::Type::Int1Ty, "land"); + PN->reserveOperandSpace(2); + PN->addIncoming(llvm::ConstantInt::getFalse(), OrigBlock); + PN->addIncoming(RHSCond, RHSBlock); + + // ZExt result to int. + return Builder.CreateZExt(PN, CGF.LLVMIntTy, "land.ext"); +} + +Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { + Value *LHSCond = CGF.EvaluateExprAsBool(E->getLHS()); + + llvm::BasicBlock *ContBlock = new llvm::BasicBlock("lor_cont"); + llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("lor_rhs"); + + llvm::BasicBlock *OrigBlock = Builder.GetInsertBlock(); + Builder.CreateCondBr(LHSCond, ContBlock, RHSBlock); + + CGF.EmitBlock(RHSBlock); + Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); + + // Reaquire the RHS block, as there may be subblocks inserted. + RHSBlock = Builder.GetInsertBlock(); + CGF.EmitBlock(ContBlock); + + // Create a PHI node. If we just evaluted the LHS condition, the result is + // true. If we evaluated both, the result is the RHS condition. + llvm::PHINode *PN = Builder.CreatePHI(llvm::Type::Int1Ty, "lor"); + PN->reserveOperandSpace(2); + PN->addIncoming(llvm::ConstantInt::getTrue(), OrigBlock); + PN->addIncoming(RHSCond, RHSBlock); + + // ZExt result to int. + return Builder.CreateZExt(PN, CGF.LLVMIntTy, "lor.ext"); +} + +Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { + CGF.EmitStmt(E->getLHS()); + return Visit(E->getRHS()); +} + +//===----------------------------------------------------------------------===// +// Other Operators +//===----------------------------------------------------------------------===// + +Value *ScalarExprEmitter:: +VisitConditionalOperator(const ConditionalOperator *E) { + llvm::BasicBlock *LHSBlock = new llvm::BasicBlock("cond.?"); + llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:"); + llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont"); + + // Evaluate the conditional, then convert it to bool. We do this explicitly + // because we need the unconverted value if this is a GNU ?: expression with + // missing middle value. + Value *CondVal = CGF.EmitScalarExpr(E->getCond()); + Value *CondBoolVal =CGF.EmitScalarConversion(CondVal, E->getCond()->getType(), + CGF.getContext().BoolTy); + Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); + + CGF.EmitBlock(LHSBlock); + + // Handle the GNU extension for missing LHS. + Value *LHS; + if (E->getLHS()) + LHS = Visit(E->getLHS()); + else // Perform promotions, to handle cases like "short ?: int" + LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType()); + + Builder.CreateBr(ContBlock); + LHSBlock = Builder.GetInsertBlock(); + + CGF.EmitBlock(RHSBlock); + + Value *RHS = Visit(E->getRHS()); + Builder.CreateBr(ContBlock); + RHSBlock = Builder.GetInsertBlock(); + + CGF.EmitBlock(ContBlock); + + if (!LHS) { + assert(E->getType()->isVoidType() && "Non-void value should have a value"); + return 0; + } + + // Create a PHI node for the real part. + llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); + PN->reserveOperandSpace(2); + PN->addIncoming(LHS, LHSBlock); + PN->addIncoming(RHS, RHSBlock); + return PN; +} + +Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { + // Emit the LHS or RHS as appropriate. + return + Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() : E->getRHS()); +} + +Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) { + return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), + E->getNumArgs(CGF.getContext())).getScalarVal(); +} + +Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { + llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress(); + + llvm::Value *V = Builder.CreateVAArg(ArgValue, ConvertType(VE->getType())); + return V; +} + +Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { + std::string str; + llvm::SmallVector EncodingRecordTypes; + CGF.getContext().getObjCEncodingForType(E->getEncodedType(), str, + EncodingRecordTypes); + + llvm::Constant *C = llvm::ConstantArray::get(str); + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, ".str", &CGF.CGM.getModule()); + llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); + llvm::Constant *Zeros[] = { Zero, Zero }; + C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2); + + return C; +} + +//===----------------------------------------------------------------------===// +// Entry Point into this File +//===----------------------------------------------------------------------===// + +/// EmitComplexExpr - Emit the computation of the specified expression of +/// complex type, ignoring the result. +Value *CodeGenFunction::EmitScalarExpr(const Expr *E) { + assert(E && !hasAggregateLLVMType(E->getType()) && + "Invalid scalar expression to emit"); + + return ScalarExprEmitter(*this).Visit(const_cast(E)); +} + +/// EmitScalarConversion - Emit a conversion from the specified type to the +/// specified destination type, both of which are LLVM scalar types. +Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy, + QualType DstTy) { + assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) && + "Invalid scalar expression to emit"); + return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy); +} + +/// EmitComplexToScalarConversion - Emit a conversion from the specified +/// complex type to the specified destination type, where the destination +/// type is an LLVM scalar type. +Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src, + QualType SrcTy, + QualType DstTy) { + assert(SrcTy->isComplexType() && !hasAggregateLLVMType(DstTy) && + "Invalid complex -> scalar conversion"); + return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy, + DstTy); +} + +Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) { + assert(V1->getType() == V2->getType() && + "Vector operands must be of the same type"); + + unsigned NumElements = + cast(V1->getType())->getNumElements(); + + va_list va; + va_start(va, V2); + + llvm::SmallVector Args; + + for (unsigned i = 0; i < NumElements; i++) { + int n = va_arg(va, int); + + assert(n >= 0 && n < (int)NumElements * 2 && + "Vector shuffle index out of bounds!"); + + Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, n)); + } + + const char *Name = va_arg(va, const char *); + va_end(va); + + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); + + return Builder.CreateShuffleVector(V1, V2, Mask, Name); +} + +llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, + unsigned NumVals, bool isSplat) +{ + llvm::Value *Vec + = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals)); + + for (unsigned i = 0, e = NumVals ; i != e; ++i) { + llvm::Value *Val = isSplat ? Vals[0] : Vals[i]; + llvm::Value *Idx = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); + Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp"); + } + + return Vec; +} diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp new file mode 100644 index 00000000000..33419a3d51d --- /dev/null +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -0,0 +1,25 @@ +//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Objective-C code as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/Expr.h" +#include "llvm/Constant.h" +using namespace clang; +using namespace CodeGen; + +llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){ + std::string S(E->getString()->getStrData(), E->getString()->getByteLength()); + return CGM.GetAddrOfConstantCFString(S); +} + diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp new file mode 100644 index 00000000000..f0d6f554d55 --- /dev/null +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -0,0 +1,97 @@ +//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides Objective-C code generation targetting the GNU runtime. +// +//===----------------------------------------------------------------------===// + +#include "CGObjCRuntime.h" +#include "llvm/Module.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/LLVMBuilder.h" +#include "llvm/ADT/SmallVector.h" + +using namespace clang::CodeGen; +using namespace clang; + +CGObjCRuntime::~CGObjCRuntime() {} + +namespace { +class CGObjCGNU : public CGObjCRuntime { +private: + llvm::Module &TheModule; +public: + CGObjCGNU(llvm::Module &M) : TheModule(M) {}; + virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder, + const llvm::Type *ReturnTy, + llvm::Value *Receiver, + llvm::Constant *Selector, + llvm::Value** ArgV, + unsigned ArgC); +}; +} // end anonymous namespace + +// Generate code for a message send expression on the GNU runtime. +// BIG FAT WARNING: Much of this code will need factoring out later. +// FIXME: This currently only handles id returns. Other return types +// need some explicit casting. +llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder, + const llvm::Type *ReturnTy, + llvm::Value *Receiver, + llvm::Constant *Selector, + llvm::Value** ArgV, + unsigned ArgC) { + // Get the selector Type. + const llvm::Type *PtrToInt8Ty = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + std::vector Str2(2, PtrToInt8Ty); + const llvm::Type *SelStructTy = llvm::StructType::get(Str2); + const llvm::Type *SelTy = llvm::PointerType::getUnqual(SelStructTy); + + // Look up the selector. + // If we haven't got the selector lookup function, look it up now. + // TODO: Factor this out and use it to implement @selector() too. + llvm::Constant *SelFunction = + TheModule.getOrInsertFunction("sel_get_uid", SelTy, PtrToInt8Ty, NULL); + // FIXME: Selectors should be statically cached, not looked up on every call. + + // TODO: Pull this out into the caller. + llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); + llvm::Constant *Ops[] = {Idx0, Idx0}; + llvm::Value *SelStr = llvm::ConstantExpr::getGetElementPtr(Selector, Ops, 2); + llvm::Value *cmd = Builder.CreateCall(SelFunction, &SelStr, &SelStr+1); + + // Look up the method implementation. + std::vector impArgTypes; + impArgTypes.push_back(Receiver->getType()); + impArgTypes.push_back(SelTy); + + // Avoid an explicit cast on the IMP by getting a version that has the right + // return type. + llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes, + true); + + llvm::Constant *lookupFunction = + TheModule.getOrInsertFunction("objc_msg_lookup", + llvm::PointerType::get(impType, 0), + Receiver->getType(), SelTy, NULL); + llvm::SmallVector lookupArgs; + lookupArgs.push_back(Receiver); + lookupArgs.push_back(cmd); + llvm::Value *imp = Builder.CreateCall(lookupFunction, + lookupArgs.begin(), lookupArgs.end()); + + // Call the method. + lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC); + return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end()); +} + +CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(llvm::Module &M) { + return new CGObjCGNU(M); +} diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h new file mode 100644 index 00000000000..d8fc60f99c0 --- /dev/null +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -0,0 +1,47 @@ +//===----- CGObjCRuntime.h - Emit LLVM Code from ASTs for a Module --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for Objective-C code generation. Concrete +// subclasses of this implement code generation for specific Objective-C +// runtime libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_OBCJRUNTIME_H +#define CLANG_CODEGEN_OBCJRUNTIME_H + +namespace llvm { + class LLVMFoldingBuilder; + class Constant; + class Type; + class Value; + class Module; +} + +namespace clang { +namespace CodeGen { + +// Implements runtime-specific code generation functions +class CGObjCRuntime { +public: + virtual ~CGObjCRuntime(); + + // Generate an Objective-C message send operation + virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder, + const llvm::Type *ReturnTy, + llvm::Value *Receiver, + llvm::Constant *Selector, + llvm::Value** ArgV, + unsigned ArgC) = 0; +}; + +CGObjCRuntime *CreateObjCRuntime(llvm::Module &M); +} +} +#endif diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp new file mode 100644 index 00000000000..5fdc61b46f8 --- /dev/null +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -0,0 +1,776 @@ +//===--- CGStmt.cpp - Emit LLVM Code from Statements ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to emit Stmt nodes as LLVM code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "clang/AST/AST.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/InlineAsm.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; +using namespace CodeGen; + +//===----------------------------------------------------------------------===// +// Statement Emission +//===----------------------------------------------------------------------===// + +void CodeGenFunction::EmitStmt(const Stmt *S) { + assert(S && "Null statement?"); + + switch (S->getStmtClass()) { + default: + // Must be an expression in a stmt context. Emit the value (to get + // side-effects) and ignore the result. + if (const Expr *E = dyn_cast(S)) { + if (!hasAggregateLLVMType(E->getType())) + EmitScalarExpr(E); + else if (E->getType()->isComplexType()) + EmitComplexExpr(E); + else + EmitAggExpr(E, 0, false); + } else { + WarnUnsupported(S, "statement"); + } + break; + case Stmt::NullStmtClass: break; + case Stmt::CompoundStmtClass: EmitCompoundStmt(cast(*S)); break; + case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; + case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; + + case Stmt::IfStmtClass: EmitIfStmt(cast(*S)); break; + case Stmt::WhileStmtClass: EmitWhileStmt(cast(*S)); break; + case Stmt::DoStmtClass: EmitDoStmt(cast(*S)); break; + case Stmt::ForStmtClass: EmitForStmt(cast(*S)); break; + + case Stmt::ReturnStmtClass: EmitReturnStmt(cast(*S)); break; + case Stmt::DeclStmtClass: EmitDeclStmt(cast(*S)); break; + + case Stmt::BreakStmtClass: EmitBreakStmt(); break; + case Stmt::ContinueStmtClass: EmitContinueStmt(); break; + case Stmt::SwitchStmtClass: EmitSwitchStmt(cast(*S)); break; + case Stmt::DefaultStmtClass: EmitDefaultStmt(cast(*S)); break; + case Stmt::CaseStmtClass: EmitCaseStmt(cast(*S)); break; + case Stmt::AsmStmtClass: EmitAsmStmt(cast(*S)); break; + } +} + +/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true, +/// this captures the expression result of the last sub-statement and returns it +/// (for use by the statement expression extension). +RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, + llvm::Value *AggLoc, bool isAggVol) { + // FIXME: handle vla's etc. + if (S.body_empty() || !isa(S.body_back())) GetLast = false; + + for (CompoundStmt::const_body_iterator I = S.body_begin(), + E = S.body_end()-GetLast; I != E; ++I) + EmitStmt(*I); + + + if (!GetLast) + return RValue::get(0); + + return EmitAnyExpr(cast(S.body_back()), AggLoc); +} + +void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB) { + // Emit a branch from this block to the next one if this was a real block. If + // this was just a fall-through block after a terminator, don't emit it. + llvm::BasicBlock *LastBB = Builder.GetInsertBlock(); + + if (LastBB->getTerminator()) { + // If the previous block is already terminated, don't touch it. + } else if (LastBB->empty() && LastBB->getValueName() == 0) { + // If the last block was an empty placeholder, remove it now. + // TODO: cache and reuse these. + Builder.GetInsertBlock()->eraseFromParent(); + } else { + // Otherwise, create a fall-through branch. + Builder.CreateBr(BB); + } + CurFn->getBasicBlockList().push_back(BB); + Builder.SetInsertPoint(BB); +} + +void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { + llvm::BasicBlock *NextBB = getBasicBlockForLabel(&S); + + EmitBlock(NextBB); + EmitStmt(S.getSubStmt()); +} + +void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { + Builder.CreateBr(getBasicBlockForLabel(S.getLabel())); + + // Emit a block after the branch so that dead code after a goto has some place + // to go. + Builder.SetInsertPoint(new llvm::BasicBlock("", CurFn)); +} + +void CodeGenFunction::EmitIfStmt(const IfStmt &S) { + // C99 6.8.4.1: The first substatement is executed if the expression compares + // unequal to 0. The condition must be a scalar type. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + llvm::BasicBlock *ContBlock = new llvm::BasicBlock("ifend"); + llvm::BasicBlock *ThenBlock = new llvm::BasicBlock("ifthen"); + llvm::BasicBlock *ElseBlock = ContBlock; + + if (S.getElse()) + ElseBlock = new llvm::BasicBlock("ifelse"); + + // Insert the conditional branch. + Builder.CreateCondBr(BoolCondVal, ThenBlock, ElseBlock); + + // Emit the 'then' code. + EmitBlock(ThenBlock); + EmitStmt(S.getThen()); + llvm::BasicBlock *BB = Builder.GetInsertBlock(); + if (isDummyBlock(BB)) { + BB->eraseFromParent(); + Builder.SetInsertPoint(ThenBlock); + } + else + Builder.CreateBr(ContBlock); + + // Emit the 'else' code if present. + if (const Stmt *Else = S.getElse()) { + EmitBlock(ElseBlock); + EmitStmt(Else); + llvm::BasicBlock *BB = Builder.GetInsertBlock(); + if (isDummyBlock(BB)) { + BB->eraseFromParent(); + Builder.SetInsertPoint(ElseBlock); + } + else + Builder.CreateBr(ContBlock); + } + + // Emit the continuation block for code after the if. + EmitBlock(ContBlock); +} + +void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { + // Emit the header for the loop, insert it, which will create an uncond br to + // it. + llvm::BasicBlock *LoopHeader = new llvm::BasicBlock("whilecond"); + EmitBlock(LoopHeader); + + // Evaluate the conditional in the while header. C99 6.8.5.1: The evaluation + // of the controlling expression takes place before each execution of the loop + // body. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + // while(1) is common, avoid extra exit blocks. Be sure + // to correctly handle break/continue though. + bool EmitBoolCondBranch = true; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + if (C->isOne()) + EmitBoolCondBranch = false; + + // Create an exit block for when the condition fails, create a block for the + // body of the loop. + llvm::BasicBlock *ExitBlock = new llvm::BasicBlock("whileexit"); + llvm::BasicBlock *LoopBody = new llvm::BasicBlock("whilebody"); + + // As long as the condition is true, go to the loop body. + if (EmitBoolCondBranch) + Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); + + // Store the blocks to use for break and continue. + BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader)); + + // Emit the loop body. + EmitBlock(LoopBody); + EmitStmt(S.getBody()); + + BreakContinueStack.pop_back(); + + // Cycle to the condition. + Builder.CreateBr(LoopHeader); + + // Emit the exit block. + EmitBlock(ExitBlock); + + // If LoopHeader is a simple forwarding block then eliminate it. + if (!EmitBoolCondBranch + && &LoopHeader->front() == LoopHeader->getTerminator()) { + LoopHeader->replaceAllUsesWith(LoopBody); + LoopHeader->getTerminator()->eraseFromParent(); + LoopHeader->eraseFromParent(); + } +} + +void CodeGenFunction::EmitDoStmt(const DoStmt &S) { + // Emit the body for the loop, insert it, which will create an uncond br to + // it. + llvm::BasicBlock *LoopBody = new llvm::BasicBlock("dobody"); + llvm::BasicBlock *AfterDo = new llvm::BasicBlock("afterdo"); + EmitBlock(LoopBody); + + llvm::BasicBlock *DoCond = new llvm::BasicBlock("docond"); + + // Store the blocks to use for break and continue. + BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond)); + + // Emit the body of the loop into the block. + EmitStmt(S.getBody()); + + BreakContinueStack.pop_back(); + + EmitBlock(DoCond); + + // C99 6.8.5.2: "The evaluation of the controlling expression takes place + // after each execution of the loop body." + + // Evaluate the conditional in the while header. + // C99 6.8.5p2/p4: The first substatement is executed if the expression + // compares unequal to 0. The condition must be a scalar type. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + // "do {} while (0)" is common in macros, avoid extra blocks. Be sure + // to correctly handle break/continue though. + bool EmitBoolCondBranch = true; + if (llvm::ConstantInt *C = dyn_cast(BoolCondVal)) + if (C->isZero()) + EmitBoolCondBranch = false; + + // As long as the condition is true, iterate the loop. + if (EmitBoolCondBranch) + Builder.CreateCondBr(BoolCondVal, LoopBody, AfterDo); + + // Emit the exit block. + EmitBlock(AfterDo); + + // If DoCond is a simple forwarding block then eliminate it. + if (!EmitBoolCondBranch && &DoCond->front() == DoCond->getTerminator()) { + DoCond->replaceAllUsesWith(AfterDo); + DoCond->getTerminator()->eraseFromParent(); + DoCond->eraseFromParent(); + } +} + +void CodeGenFunction::EmitForStmt(const ForStmt &S) { + // FIXME: What do we do if the increment (f.e.) contains a stmt expression, + // which contains a continue/break? + // TODO: We could keep track of whether the loop body contains any + // break/continue statements and not create unnecessary blocks (like + // "afterfor" for a condless loop) if it doesn't. + + // Evaluate the first part before the loop. + if (S.getInit()) + EmitStmt(S.getInit()); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = new llvm::BasicBlock("forcond"); + llvm::BasicBlock *AfterFor = new llvm::BasicBlock("afterfor"); + + EmitBlock(CondBlock); + + // Evaluate the condition if present. If not, treat it as a non-zero-constant + // according to 6.8.5.3p2, aka, true. + if (S.getCond()) { + // C99 6.8.5p2/p4: The first substatement is executed if the expression + // compares unequal to 0. The condition must be a scalar type. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + + // As long as the condition is true, iterate the loop. + llvm::BasicBlock *ForBody = new llvm::BasicBlock("forbody"); + Builder.CreateCondBr(BoolCondVal, ForBody, AfterFor); + EmitBlock(ForBody); + } else { + // Treat it as a non-zero constant. Don't even create a new block for the + // body, just fall into it. + } + + // If the for loop doesn't have an increment we can just use the + // condition as the continue block. + llvm::BasicBlock *ContinueBlock; + if (S.getInc()) + ContinueBlock = new llvm::BasicBlock("forinc"); + else + ContinueBlock = CondBlock; + + // Store the blocks to use for break and continue. + BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock)); + + // If the condition is true, execute the body of the for stmt. + EmitStmt(S.getBody()); + + BreakContinueStack.pop_back(); + + if (S.getInc()) + EmitBlock(ContinueBlock); + + // If there is an increment, emit it next. + if (S.getInc()) + EmitStmt(S.getInc()); + + // Finally, branch back up to the condition for the next iteration. + Builder.CreateBr(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor); +} + +/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand +/// if the function returns void, or may be missing one if the function returns +/// non-void. Fun stuff :). +void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { + // Emit the result value, even if unused, to evalute the side effects. + const Expr *RV = S.getRetValue(); + + QualType FnRetTy = CurFuncDecl->getType().getCanonicalType(); + FnRetTy = cast(FnRetTy)->getResultType(); + + if (FnRetTy->isVoidType()) { + // If the function returns void, emit ret void. + Builder.CreateRetVoid(); + } else if (RV == 0) { + // Handle "return;" in a function that returns a value. + const llvm::Type *RetTy = CurFn->getFunctionType()->getReturnType(); + if (RetTy == llvm::Type::VoidTy) + Builder.CreateRetVoid(); // struct return etc. + else + Builder.CreateRet(llvm::UndefValue::get(RetTy)); + } else if (!hasAggregateLLVMType(RV->getType())) { + Builder.CreateRet(EmitScalarExpr(RV)); + } else if (RV->getType()->isComplexType()) { + llvm::Value *SRetPtr = CurFn->arg_begin(); + EmitComplexExprIntoAddr(RV, SRetPtr, false); + } else { + llvm::Value *SRetPtr = CurFn->arg_begin(); + EmitAggExpr(RV, SRetPtr, false); + } + + // Emit a block after the branch so that dead code after a return has some + // place to go. + EmitBlock(new llvm::BasicBlock()); +} + +void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) { + for (const ScopedDecl *Decl = S.getDecl(); Decl; + Decl = Decl->getNextDeclarator()) + EmitDecl(*Decl); +} + +void CodeGenFunction::EmitBreakStmt() { + assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!"); + + llvm::BasicBlock *Block = BreakContinueStack.back().BreakBlock; + Builder.CreateBr(Block); + EmitBlock(new llvm::BasicBlock()); +} + +void CodeGenFunction::EmitContinueStmt() { + assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); + + llvm::BasicBlock *Block = BreakContinueStack.back().ContinueBlock; + Builder.CreateBr(Block); + EmitBlock(new llvm::BasicBlock()); +} + +/// EmitCaseStmtRange - If case statement range is not too big then +/// add multiple cases to switch instruction, one for each value within +/// the range. If range is too big then emit "if" condition check. +void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { + assert (S.getRHS() && "Unexpected RHS value in CaseStmt"); + + const Expr *L = S.getLHS(); + const Expr *R = S.getRHS(); + llvm::ConstantInt *LV = cast(EmitScalarExpr(L)); + llvm::ConstantInt *RV = cast(EmitScalarExpr(R)); + llvm::APInt LHS = LV->getValue(); + const llvm::APInt &RHS = RV->getValue(); + + llvm::APInt Range = RHS - LHS; + if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) { + // Range is small enough to add multiple switch instruction cases. + StartBlock("sw.bb"); + llvm::BasicBlock *CaseDest = Builder.GetInsertBlock(); + SwitchInsn->addCase(LV, CaseDest); + LHS++; + while (LHS != RHS) { + SwitchInsn->addCase(llvm::ConstantInt::get(LHS), CaseDest); + LHS++; + } + SwitchInsn->addCase(RV, CaseDest); + EmitStmt(S.getSubStmt()); + return; + } + + // The range is too big. Emit "if" condition. + llvm::BasicBlock *FalseDest = NULL; + llvm::BasicBlock *CaseDest = new llvm::BasicBlock("sw.bb"); + + // If we have already seen one case statement range for this switch + // instruction then piggy-back otherwise use default block as false + // destination. + if (CaseRangeBlock) + FalseDest = CaseRangeBlock; + else + FalseDest = SwitchInsn->getDefaultDest(); + + // Start new block to hold case statement range check instructions. + StartBlock("case.range"); + CaseRangeBlock = Builder.GetInsertBlock(); + + // Emit range check. + llvm::Value *Diff = + Builder.CreateSub(SwitchInsn->getCondition(), LV, "tmp"); + llvm::Value *Cond = + Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(Range), "tmp"); + Builder.CreateCondBr(Cond, CaseDest, FalseDest); + + // Now emit case statement body. + EmitBlock(CaseDest); + EmitStmt(S.getSubStmt()); +} + +void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { + if (S.getRHS()) { + EmitCaseStmtRange(S); + return; + } + + StartBlock("sw.bb"); + llvm::BasicBlock *CaseDest = Builder.GetInsertBlock(); + llvm::APSInt CaseVal(32); + S.getLHS()->isIntegerConstantExpr(CaseVal, getContext()); + llvm::ConstantInt *LV = llvm::ConstantInt::get(CaseVal); + SwitchInsn->addCase(LV, CaseDest); + EmitStmt(S.getSubStmt()); +} + +void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) { + StartBlock("sw.default"); + // Current insert block is the default destination. + SwitchInsn->setSuccessor(0, Builder.GetInsertBlock()); + EmitStmt(S.getSubStmt()); +} + +void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { + llvm::Value *CondV = EmitScalarExpr(S.getCond()); + + // Handle nested switch statements. + llvm::SwitchInst *SavedSwitchInsn = SwitchInsn; + llvm::BasicBlock *SavedCRBlock = CaseRangeBlock; + CaseRangeBlock = NULL; + + // Create basic block to hold stuff that comes after switch statement. + // Initially use it to hold DefaultStmt. + llvm::BasicBlock *NextBlock = new llvm::BasicBlock("after.sw"); + SwitchInsn = Builder.CreateSwitch(CondV, NextBlock); + + // All break statements jump to NextBlock. If BreakContinueStack is non empty + // then reuse last ContinueBlock. + llvm::BasicBlock *ContinueBlock = NULL; + if (!BreakContinueStack.empty()) + ContinueBlock = BreakContinueStack.back().ContinueBlock; + BreakContinueStack.push_back(BreakContinue(NextBlock, ContinueBlock)); + + // Emit switch body. + EmitStmt(S.getBody()); + BreakContinueStack.pop_back(); + + // If one or more case statement range is seen then use CaseRangeBlock + // as the default block. False edge of CaseRangeBlock will lead to + // original default block. + if (CaseRangeBlock) + SwitchInsn->setSuccessor(0, CaseRangeBlock); + + // Prune insert block if it is dummy. + llvm::BasicBlock *BB = Builder.GetInsertBlock(); + if (isDummyBlock(BB)) + BB->eraseFromParent(); + else // Otherwise, branch to continuation. + Builder.CreateBr(NextBlock); + + // Place NextBlock as the new insert point. + CurFn->getBasicBlockList().push_back(NextBlock); + Builder.SetInsertPoint(NextBlock); + SwitchInsn = SavedSwitchInsn; + CaseRangeBlock = SavedCRBlock; +} + +static inline std::string ConvertAsmString(const char *Start, + unsigned NumOperands, + bool IsSimple) +{ + static unsigned AsmCounter = 0; + + AsmCounter++; + + std::string Result; + if (IsSimple) { + while (*Start) { + switch (*Start) { + default: + Result += *Start; + break; + case '$': + Result += "$$"; + break; + } + + Start++; + } + + return Result; + } + + while (*Start) { + switch (*Start) { + default: + Result += *Start; + break; + case '$': + Result += "$$"; + break; + case '%': + // Escaped character + Start++; + if (!*Start) { + // FIXME: This should be caught during Sema. + assert(0 && "Trailing '%' in asm string."); + } + + char EscapedChar = *Start; + if (EscapedChar == '%') { + // Escaped percentage sign. + Result += '%'; + } + else if (EscapedChar == '=') { + // Generate an unique ID. + Result += llvm::utostr(AsmCounter); + } else if (isdigit(EscapedChar)) { + // %n - Assembler operand n + char *End; + + unsigned long n = strtoul(Start, &End, 10); + if (Start == End) { + // FIXME: This should be caught during Sema. + assert(0 && "Missing operand!"); + } else if (n >= NumOperands) { + // FIXME: This should be caught during Sema. + assert(0 && "Operand number out of range!"); + } + + Result += '$' + llvm::utostr(n); + Start = End - 1; + } else if (isalpha(EscapedChar)) { + char *End; + + unsigned long n = strtoul(Start + 1, &End, 10); + if (Start == End) { + // FIXME: This should be caught during Sema. + assert(0 && "Missing operand!"); + } else if (n >= NumOperands) { + // FIXME: This should be caught during Sema. + assert(0 && "Operand number out of range!"); + } + + Result += "${" + llvm::utostr(n) + ':' + EscapedChar + '}'; + Start = End - 1; + } else { + assert(0 && "Unhandled asm escaped character!"); + } + } + Start++; + } + + return Result; +} + +static std::string SimplifyConstraint(const char* Constraint, + TargetInfo &Target) { + std::string Result; + + while (*Constraint) { + switch (*Constraint) { + default: + Result += Target.convertConstraint(*Constraint); + break; + // Ignore these + case '*': + case '?': + case '!': + break; + case 'g': + Result += "imr"; + break; + } + + Constraint++; + } + + return Result; +} + +void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { + std::string AsmString = + ConvertAsmString(std::string(S.getAsmString()->getStrData(), + S.getAsmString()->getByteLength()).c_str(), + S.getNumOutputs() + S.getNumInputs(), S.isSimple()); + + std::string Constraints; + + llvm::Value *ResultAddr = 0; + const llvm::Type *ResultType = llvm::Type::VoidTy; + + std::vector ArgTypes; + std::vector Args; + + // Keep track of inout constraints. + std::string InOutConstraints; + std::vector InOutArgs; + std::vector InOutArgTypes; + + for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { + std::string OutputConstraint(S.getOutputConstraint(i)->getStrData(), + S.getOutputConstraint(i)->getByteLength()); + + TargetInfo::ConstraintInfo Info; + bool result = Target.validateOutputConstraint(OutputConstraint.c_str(), + Info); + assert(result && "Failed to parse output constraint"); + + // Simplify the output constraint. + OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target); + + LValue Dest = EmitLValue(S.getOutputExpr(i)); + const llvm::Type *DestValueType = + cast(Dest.getAddress()->getType())->getElementType(); + + // If the first output operand is not a memory dest, we'll + // make it the return value. + if (i == 0 && !(Info & TargetInfo::CI_AllowsMemory) && + DestValueType->isFirstClassType()) { + ResultAddr = Dest.getAddress(); + ResultType = DestValueType; + Constraints += "=" + OutputConstraint; + } else { + ArgTypes.push_back(Dest.getAddress()->getType()); + Args.push_back(Dest.getAddress()); + if (i != 0) + Constraints += ','; + Constraints += "=*"; + Constraints += OutputConstraint; + } + + if (Info & TargetInfo::CI_ReadWrite) { + // FIXME: This code should be shared with the code that handles inputs. + InOutConstraints += ','; + + const Expr *InputExpr = S.getOutputExpr(i); + llvm::Value *Arg; + if ((Info & TargetInfo::CI_AllowsRegister) || + !(Info & TargetInfo::CI_AllowsMemory)) { + if (ConvertType(InputExpr->getType())->isFirstClassType()) { + Arg = EmitScalarExpr(InputExpr); + } else { + assert(0 && "FIXME: Implement passing non first class types as inputs"); + } + } else { + LValue Dest = EmitLValue(InputExpr); + Arg = Dest.getAddress(); + InOutConstraints += '*'; + } + + InOutArgTypes.push_back(Arg->getType()); + InOutArgs.push_back(Arg); + InOutConstraints += OutputConstraint; + } + } + + unsigned NumConstraints = S.getNumOutputs() + S.getNumInputs(); + + for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { + const Expr *InputExpr = S.getInputExpr(i); + + std::string InputConstraint(S.getInputConstraint(i)->getStrData(), + S.getInputConstraint(i)->getByteLength()); + + TargetInfo::ConstraintInfo Info; + bool result = Target.validateInputConstraint(InputConstraint.c_str(), + NumConstraints, + Info); + assert(result && "Failed to parse input constraint"); + + if (i != 0 || S.getNumOutputs() > 0) + Constraints += ','; + + // Simplify the input constraint. + InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target); + + llvm::Value *Arg; + + if ((Info & TargetInfo::CI_AllowsRegister) || + !(Info & TargetInfo::CI_AllowsMemory)) { + if (ConvertType(InputExpr->getType())->isFirstClassType()) { + Arg = EmitScalarExpr(InputExpr); + } else { + assert(0 && "FIXME: Implement passing non first class types as inputs"); + } + } else { + LValue Dest = EmitLValue(InputExpr); + Arg = Dest.getAddress(); + Constraints += '*'; + } + + ArgTypes.push_back(Arg->getType()); + Args.push_back(Arg); + Constraints += InputConstraint; + } + + // Append the "input" part of inout constraints last. + for (unsigned i = 0, e = InOutArgs.size(); i != e; i++) { + ArgTypes.push_back(InOutArgTypes[i]); + Args.push_back(InOutArgs[i]); + } + Constraints += InOutConstraints; + + // Clobbers + for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { + std::string Clobber(S.getClobber(i)->getStrData(), + S.getClobber(i)->getByteLength()); + + Clobber = Target.getNormalizedGCCRegisterName(Clobber.c_str()); + + if (i != 0 || NumConstraints != 0) + Constraints += ','; + + Constraints += "~{"; + Constraints += Clobber; + Constraints += '}'; + } + + // Add machine specific clobbers + if (const char *C = Target.getClobbers()) { + if (!Constraints.empty()) + Constraints += ','; + Constraints += C; + } + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(ResultType, ArgTypes, false); + + llvm::InlineAsm *IA = + llvm::InlineAsm::get(FTy, AsmString, Constraints, + S.isVolatile() || S.getNumOutputs() == 0); + llvm::Value *Result = Builder.CreateCall(IA, Args.begin(), Args.end(), ""); + if (ResultAddr) + Builder.CreateStore(Result, ResultAddr); +} diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp new file mode 100644 index 00000000000..49f23f27c34 --- /dev/null +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -0,0 +1,182 @@ +//===--- CodeGenFunction.cpp - Emit LLVM Code from ASTs for a Function ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This coordinates the per-function state used while generating code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/AST/AST.h" +#include "llvm/CallingConv.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Support/CFG.h" +using namespace clang; +using namespace CodeGen; + +CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) + : CGM(cgm), Target(CGM.getContext().Target), SwitchInsn(NULL), + CaseRangeBlock(NULL) {} + +ASTContext &CodeGenFunction::getContext() const { + return CGM.getContext(); +} + + +llvm::BasicBlock *CodeGenFunction::getBasicBlockForLabel(const LabelStmt *S) { + llvm::BasicBlock *&BB = LabelMap[S]; + if (BB) return BB; + + // Create, but don't insert, the new block. + return BB = new llvm::BasicBlock(S->getName()); +} + +llvm::Constant * +CodeGenFunction::GetAddrOfStaticLocalVar(const BlockVarDecl *BVD) { + return cast(LocalDeclMap[BVD]); +} + +const llvm::Type *CodeGenFunction::ConvertType(QualType T) { + return CGM.getTypes().ConvertType(T); +} + +bool CodeGenFunction::hasAggregateLLVMType(QualType T) { + return !T->isRealType() && !T->isPointerType() && !T->isReferenceType() && + !T->isVoidType() && !T->isVectorType() && !T->isFunctionType(); +} + + +void CodeGenFunction::GenerateCode(const FunctionDecl *FD) { + LLVMIntTy = ConvertType(getContext().IntTy); + LLVMPointerWidth = static_cast( + getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy))); + + CurFuncDecl = FD; + CurFn = cast(CGM.GetAddrOfFunctionDecl(FD, true)); + assert(CurFn->isDeclaration() && "Function already has body?"); + + // TODO: Set up linkage and many other things. Note, this is a simple + // approximation of what we really want. + if (FD->getAttr()) + CurFn->setLinkage(llvm::Function::DLLImportLinkage); + else if (FD->getAttr()) + CurFn->setLinkage(llvm::Function::DLLExportLinkage); + else if (FD->getAttr() || FD->isInline()) + CurFn->setLinkage(llvm::Function::WeakLinkage); + else if (FD->getStorageClass() == FunctionDecl::Static) + CurFn->setLinkage(llvm::Function::InternalLinkage); + + if (FD->getAttr()) + CurFn->setCallingConv(llvm::CallingConv::Fast); + + if (const VisibilityAttr *attr = FD->getAttr()) + CurFn->setVisibility(attr->getVisibility()); + // FIXME: else handle -fvisibility + + + unsigned FuncAttrs = 0; + if (FD->getAttr()) + FuncAttrs |= llvm::ParamAttr::NoUnwind; + if (FD->getAttr()) + FuncAttrs |= llvm::ParamAttr::NoReturn; + + if (FuncAttrs) { + llvm::ParamAttrsWithIndex PAWI = + llvm::ParamAttrsWithIndex::get(0, FuncAttrs); + CurFn->setParamAttrs(llvm::PAListPtr::get(&PAWI, 1)); + } + + llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", CurFn); + + // Create a marker to make it easy to insert allocas into the entryblock + // later. Don't create this with the builder, because we don't want it + // folded. + llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty); + AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "allocapt", + EntryBB); + + Builder.SetInsertPoint(EntryBB); + + // Emit allocs for param decls. Give the LLVM Argument nodes names. + llvm::Function::arg_iterator AI = CurFn->arg_begin(); + + // Name the struct return argument. + if (hasAggregateLLVMType(FD->getResultType())) { + AI->setName("agg.result"); + ++AI; + } + + for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i, ++AI) { + assert(AI != CurFn->arg_end() && "Argument mismatch!"); + EmitParmDecl(*FD->getParamDecl(i), AI); + } + + // Emit the function body. + EmitStmt(FD->getBody()); + + // Emit a return for code that falls off the end. If insert point + // is a dummy block with no predecessors then remove the block itself. + llvm::BasicBlock *BB = Builder.GetInsertBlock(); + if (isDummyBlock(BB)) + BB->eraseFromParent(); + else { + // FIXME: if this is C++ main, this should return 0. + if (CurFn->getReturnType() == llvm::Type::VoidTy) + Builder.CreateRetVoid(); + else + Builder.CreateRet(llvm::UndefValue::get(CurFn->getReturnType())); + } + assert(BreakContinueStack.empty() && + "mismatched push/pop in break/continue stack!"); + + // Remove the AllocaInsertPt instruction, which is just a convenience for us. + AllocaInsertPt->eraseFromParent(); + AllocaInsertPt = 0; + + // Verify that the function is well formed. + assert(!verifyFunction(*CurFn)); +} + +/// isDummyBlock - Return true if BB is an empty basic block +/// with no predecessors. +bool CodeGenFunction::isDummyBlock(const llvm::BasicBlock *BB) { + if (BB->empty() && pred_begin(BB) == pred_end(BB)) + return true; + return false; +} + +/// StartBlock - Start new block named N. If insert block is a dummy block +/// then reuse it. +void CodeGenFunction::StartBlock(const char *N) { + llvm::BasicBlock *BB = Builder.GetInsertBlock(); + if (!isDummyBlock(BB)) + EmitBlock(new llvm::BasicBlock(N)); + else + BB->setName(N); +} + +/// getCGRecordLayout - Return record layout info. +const CGRecordLayout *CodeGenFunction::getCGRecordLayout(CodeGenTypes &CGT, + QualType Ty) { + const RecordType *RTy = Ty->getAsRecordType(); + assert (RTy && "Unexpected type. RecordType expected here."); + + return CGT.getCGRecordLayout(RTy->getDecl()); +} + +/// WarnUnsupported - Print out a warning that codegen doesn't support the +/// specified stmt yet. +void CodeGenFunction::WarnUnsupported(const Stmt *S, const char *Type) { + CGM.WarnUnsupported(S, Type); +} + diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h new file mode 100644 index 00000000000..509e8296d20 --- /dev/null +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -0,0 +1,486 @@ +//===--- CodeGenFunction.h - Per-Function state for LLVM CodeGen ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the internal per-function state used for llvm translation. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H +#define CLANG_CODEGEN_CODEGENFUNCTION_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/LLVMBuilder.h" +#include + +namespace llvm { + class Module; +} + +namespace clang { + class ASTContext; + class Decl; + class FunctionDecl; + class TargetInfo; + class QualType; + class FunctionTypeProto; + + class Stmt; + class CompoundStmt; + class LabelStmt; + class GotoStmt; + class IfStmt; + class WhileStmt; + class DoStmt; + class ForStmt; + class ReturnStmt; + class DeclStmt; + class CaseStmt; + class DefaultStmt; + class SwitchStmt; + class AsmStmt; + + class Expr; + class DeclRefExpr; + class StringLiteral; + class IntegerLiteral; + class FloatingLiteral; + class CharacterLiteral; + class TypesCompatibleExpr; + + class ImplicitCastExpr; + class CastExpr; + class CallExpr; + class UnaryOperator; + class BinaryOperator; + class CompoundAssignOperator; + class ArraySubscriptExpr; + class OCUVectorElementExpr; + class ConditionalOperator; + class ChooseExpr; + class PreDefinedExpr; + class ObjCStringLiteral; + class MemberExpr; + + class BlockVarDecl; + class EnumConstantDecl; + class ParmVarDecl; + class FieldDecl; +namespace CodeGen { + class CodeGenModule; + class CodeGenTypes; + class CGRecordLayout; + +/// RValue - This trivial value class is used to represent the result of an +/// expression that is evaluated. It can be one of three things: either a +/// 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; + + // FIXME: Aggregate rvalues need to retain information about whether they are + // volatile or not. +public: + + bool isScalar() const { return Flavor == Scalar; } + bool isComplex() const { return Flavor == Complex; } + bool isAggregate() const { return Flavor == Aggregate; } + + /// getScalar() - Return the Value* of this scalar value. + llvm::Value *getScalarVal() const { + assert(isScalar() && "Not a scalar!"); + return V1; + } + + /// getComplexVal - Return the real/imag components of this complex value. + /// + std::pair getComplexVal() const { + return std::pair(V1, V2); + } + + /// getAggregateAddr() - Return the Value* of the address of the aggregate. + llvm::Value *getAggregateAddr() const { + assert(isAggregate() && "Not an aggregate!"); + return V1; + } + + static RValue get(llvm::Value *V) { + RValue ER; + ER.V1 = V; + ER.Flavor = Scalar; + return ER; + } + static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { + RValue ER; + ER.V1 = V1; + ER.V2 = V2; + ER.Flavor = Complex; + return ER; + } + static RValue getComplex(const std::pair &C) { + RValue ER; + ER.V1 = C.first; + ER.V2 = C.second; + ER.Flavor = Complex; + return ER; + } + static RValue getAggregate(llvm::Value *V) { + RValue ER; + ER.V1 = V; + ER.Flavor = Aggregate; + return ER; + } +}; + + +/// LValue - This represents an lvalue references. Because C/C++ allow +/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a +/// bitrange. +class LValue { + // FIXME: Volatility. Restrict? + // alignment? + + enum { + Simple, // This is a normal l-value, use getAddress(). + VectorElt, // This is a vector element l-value (V[i]), use getVector* + BitField, // This is a bitfield l-value, use getBitfield*. + OCUVectorElt // This is an ocu vector subset, use getOCUVectorComp + } LVType; + + llvm::Value *V; + + union { + llvm::Value *VectorIdx; // Index into a vector subscript: V[i] + unsigned VectorElts; // Encoded OCUVector element subset: V.xyx + struct { + unsigned short StartBit; + unsigned short Size; + bool IsSigned; + } BitfieldData; // BitField start bit and size + }; +public: + bool isSimple() const { return LVType == Simple; } + bool isVectorElt() const { return LVType == VectorElt; } + bool isBitfield() const { return LVType == BitField; } + bool isOCUVectorElt() const { return LVType == OCUVectorElt; } + + // simple lvalue + llvm::Value *getAddress() const { assert(isSimple()); return V; } + // vector elt lvalue + llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; } + llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; } + // ocu vector elements. + llvm::Value *getOCUVectorAddr() const { assert(isOCUVectorElt()); return V; } + unsigned getOCUVectorElts() const { + assert(isOCUVectorElt()); + return VectorElts; + } + // bitfield lvalue + llvm::Value *getBitfieldAddr() const { assert(isBitfield()); return V; } + unsigned short getBitfieldStartBit() const { + assert(isBitfield()); + return BitfieldData.StartBit; + } + unsigned short getBitfieldSize() const { + assert(isBitfield()); + return BitfieldData.Size; + } + bool isBitfieldSigned() const { + assert(isBitfield()); + return BitfieldData.IsSigned; + } + + static LValue MakeAddr(llvm::Value *V) { + LValue R; + R.LVType = Simple; + R.V = V; + return R; + } + + static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx) { + LValue R; + R.LVType = VectorElt; + R.V = Vec; + R.VectorIdx = Idx; + return R; + } + + static LValue MakeOCUVectorElt(llvm::Value *Vec, unsigned Elements) { + LValue R; + R.LVType = OCUVectorElt; + R.V = Vec; + R.VectorElts = Elements; + return R; + } + + static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit, + unsigned short Size, bool IsSigned) { + LValue R; + R.LVType = BitField; + R.V = V; + R.BitfieldData.StartBit = StartBit; + R.BitfieldData.Size = Size; + R.BitfieldData.IsSigned = IsSigned; + return R; + } +}; + +/// CodeGenFunction - This class organizes the per-function state that is used +/// while generating LLVM code. +class CodeGenFunction { +public: + CodeGenModule &CGM; // Per-module state. + TargetInfo &Target; + + typedef std::pair ComplexPairTy; + llvm::LLVMFoldingBuilder Builder; + + const FunctionDecl *CurFuncDecl; + llvm::Function *CurFn; + + /// AllocaInsertPoint - This is an instruction in the entry block before which + /// we prefer to insert allocas. + llvm::Instruction *AllocaInsertPt; + + const llvm::Type *LLVMIntTy; + uint32_t LLVMPointerWidth; + +private: + /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C + /// decls. + llvm::DenseMap LocalDeclMap; + + /// LabelMap - This keeps track of the LLVM basic block for each C label. + llvm::DenseMap LabelMap; + + // BreakContinueStack - This keeps track of where break and continue + // statements should jump to. + struct BreakContinue { + BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb) + : BreakBlock(bb), ContinueBlock(cb) {} + + llvm::BasicBlock *BreakBlock; + llvm::BasicBlock *ContinueBlock; + }; + llvm::SmallVector BreakContinueStack; + + /// SwitchInsn - This is nearest current switch instruction. It is null if + /// if current context is not in a switch. + llvm::SwitchInst *SwitchInsn; + + /// CaseRangeBlock - This block holds if condition check for last case + /// statement range in current switch instruction. + llvm::BasicBlock *CaseRangeBlock; + +public: + CodeGenFunction(CodeGenModule &cgm); + + ASTContext &getContext() const; + + void GenerateCode(const FunctionDecl *FD); + + const llvm::Type *ConvertType(QualType T); + + /// hasAggregateLLVMType - Return true if the specified AST type will map into + /// an aggregate LLVM type or is void. + static bool hasAggregateLLVMType(QualType T); + + /// getBasicBlockForLabel - Return the LLVM basicblock that the specified + /// label maps to. + llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S); + + + void EmitBlock(llvm::BasicBlock *BB); + + /// WarnUnsupported - Print out a warning that codegen doesn't support the + /// specified stmt yet. + void WarnUnsupported(const Stmt *S, const char *Type); + + //===--------------------------------------------------------------------===// + // Helpers + //===--------------------------------------------------------------------===// + + /// CreateTempAlloca - This creates a alloca and inserts it into the entry + /// block. + llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, + const char *Name = "tmp"); + + /// EvaluateExprAsBool - Perform the usual unary conversions on the specified + /// expression and compare the result against zero, returning an Int1Ty value. + llvm::Value *EvaluateExprAsBool(const Expr *E); + + /// EmitAnyExpr - Emit code to compute the specified expression which can have + /// any type. The result is returned as an RValue struct. If this is an + /// aggregate expression, the aggloc/agglocvolatile arguments indicate where + /// the result should be returned. + RValue EmitAnyExpr(const Expr *E, llvm::Value *AggLoc = 0, + bool isAggLocVolatile = false); + + /// isDummyBlock - Return true if BB is an empty basic block + /// with no predecessors. + static bool isDummyBlock(const llvm::BasicBlock *BB); + + /// StartBlock - Start new block named N. If insert block is a dummy block + /// then reuse it. + void StartBlock(const char *N); + + /// getCGRecordLayout - Return record layout info. + const CGRecordLayout *getCGRecordLayout(CodeGenTypes &CGT, QualType RTy); + + /// GetAddrOfStaticLocalVar - Return the address of a static local variable. + llvm::Constant *GetAddrOfStaticLocalVar(const BlockVarDecl *BVD); + //===--------------------------------------------------------------------===// + // Declaration Emission + //===--------------------------------------------------------------------===// + + void EmitDecl(const Decl &D); + void EmitEnumConstantDecl(const EnumConstantDecl &D); + void EmitBlockVarDecl(const BlockVarDecl &D); + void EmitLocalBlockVarDecl(const BlockVarDecl &D); + void EmitStaticBlockVarDecl(const BlockVarDecl &D); + void EmitParmDecl(const ParmVarDecl &D, llvm::Value *Arg); + + //===--------------------------------------------------------------------===// + // Statement Emission + //===--------------------------------------------------------------------===// + + void EmitStmt(const Stmt *S); + RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false, + llvm::Value *AggLoc = 0, bool isAggVol = false); + void EmitLabelStmt(const LabelStmt &S); + void EmitGotoStmt(const GotoStmt &S); + void EmitIfStmt(const IfStmt &S); + void EmitWhileStmt(const WhileStmt &S); + void EmitDoStmt(const DoStmt &S); + void EmitForStmt(const ForStmt &S); + void EmitReturnStmt(const ReturnStmt &S); + void EmitDeclStmt(const DeclStmt &S); + void EmitBreakStmt(); + void EmitContinueStmt(); + void EmitSwitchStmt(const SwitchStmt &S); + void EmitDefaultStmt(const DefaultStmt &S); + void EmitCaseStmt(const CaseStmt &S); + void EmitCaseStmtRange(const CaseStmt &S); + void EmitAsmStmt(const AsmStmt &S); + + //===--------------------------------------------------------------------===// + // LValue Expression Emission + //===--------------------------------------------------------------------===// + + /// EmitLValue - Emit code to compute a designator that specifies the location + /// of the expression. + /// + /// This can return one of two things: a simple address or a bitfield + /// reference. In either case, the LLVM Value* in the LValue structure is + /// guaranteed to be an LLVM pointer type. + /// + /// If this returns a bitfield reference, nothing about the pointee type of + /// the LLVM value is known: For example, it may not be a pointer to an + /// integer. + /// + /// If this returns a normal address, and if the lvalue's C type is fixed + /// size, this method guarantees that the returned pointer type will point to + /// an LLVM type of the same size of the lvalue's type. If the lvalue has a + /// variable length type, this is not possible. + /// + LValue EmitLValue(const Expr *E); + + /// EmitLoadOfLValue - Given an expression that represents a value lvalue, + /// this method emits the address of the lvalue, then loads the result as an + /// rvalue, returning the rvalue. + RValue EmitLoadOfLValue(LValue V, QualType LVType); + RValue EmitLoadOfOCUElementLValue(LValue V, QualType LVType); + RValue EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType); + + + /// EmitStoreThroughLValue - Store the specified rvalue into the specified + /// lvalue, where both are guaranteed to the have the same type, and that type + /// is 'Ty'. + void EmitStoreThroughLValue(RValue Src, LValue Dst, QualType Ty); + void EmitStoreThroughOCUComponentLValue(RValue Src, LValue Dst, QualType Ty); + void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty); + + // Note: only availabe for agg return types + LValue EmitCallExprLValue(const CallExpr *E); + + LValue EmitDeclRefLValue(const DeclRefExpr *E); + LValue EmitStringLiteralLValue(const StringLiteral *E); + LValue EmitPreDefinedLValue(const PreDefinedExpr *E); + LValue EmitUnaryOpLValue(const UnaryOperator *E); + LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); + LValue EmitOCUVectorElementExpr(const OCUVectorElementExpr *E); + LValue EmitMemberExpr(const MemberExpr *E); + + LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field, + bool isUnion); + + //===--------------------------------------------------------------------===// + // Scalar Expression Emission + //===--------------------------------------------------------------------===// + + RValue EmitCallExpr(const CallExpr *E); + RValue EmitCallExpr(Expr *FnExpr, Expr *const *Args, unsigned NumArgs); + RValue EmitCallExpr(llvm::Value *Callee, QualType FnType, + Expr *const *Args, unsigned NumArgs); + RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + + llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + + llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...); + llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals, + bool isSplat = false); + + llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); + + //===--------------------------------------------------------------------===// + // Expression Emission + //===--------------------------------------------------------------------===// + + // Expressions are broken into three classes: scalar, complex, aggregate. + + /// EmitScalarExpr - Emit the computation of the specified expression of + /// LLVM scalar type, returning the result. + llvm::Value *EmitScalarExpr(const Expr *E); + + /// EmitScalarConversion - Emit a conversion from the specified type to the + /// specified destination type, both of which are LLVM scalar types. + llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy, + QualType DstTy); + + /// EmitComplexToScalarConversion - Emit a conversion from the specified + /// complex type to the specified destination type, where the destination + /// type is an LLVM scalar type. + llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy, + QualType DstTy); + + + /// EmitAggExpr - Emit the computation of the specified expression of + /// aggregate type. The result is computed into DestPtr. Note that if + /// DestPtr is null, the value of the aggregate expression is not needed. + void EmitAggExpr(const Expr *E, llvm::Value *DestPtr, bool VolatileDest); + + /// EmitComplexExpr - Emit the computation of the specified expression of + /// complex type, returning the result. + ComplexPairTy EmitComplexExpr(const Expr *E); + + /// EmitComplexExprIntoAddr - Emit the computation of the specified expression + /// of complex type, storing into the specified Value*. + void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr, + bool DestIsVolatile); + /// LoadComplexFromAddr - Load a complex number from the specified address. + ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile); +}; +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp new file mode 100644 index 00000000000..43f399a61f2 --- /dev/null +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -0,0 +1,509 @@ +//===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This coordinates the per-module state used while generating code. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "CodeGenFunction.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/CallingConv.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Intrinsics.h" +#include +using namespace clang; +using namespace CodeGen; + + +CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO, + llvm::Module &M, const llvm::TargetData &TD, + Diagnostic &diags) + : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags), + Types(C, M, TD), MemCpyFn(0), MemSetFn(0), CFConstantStringClassRef(0) { + //TODO: Make this selectable at runtime + Runtime = CreateObjCRuntime(M); +} + +CodeGenModule::~CodeGenModule() { + EmitGlobalCtors(); + delete Runtime; +} + +/// WarnUnsupported - Print out a warning that codegen doesn't support the +/// specified stmt yet. +void CodeGenModule::WarnUnsupported(const Stmt *S, const char *Type) { + unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning, + "cannot codegen this %0 yet"); + SourceRange Range = S->getSourceRange(); + std::string Msg = Type; + getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID, + &Msg, 1, &Range, 1); +} + +/// WarnUnsupported - Print out a warning that codegen doesn't support the +/// specified decl yet. +void CodeGenModule::WarnUnsupported(const Decl *D, const char *Type) { + unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning, + "cannot codegen this %0 yet"); + std::string Msg = Type; + getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID, + &Msg, 1); +} + +/// AddGlobalCtor - Add a function to the list that will be called before +/// main() runs. +void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor) { + // TODO: Type coercion of void()* types. + GlobalCtors.push_back(Ctor); +} + +void CodeGenModule::EmitGlobalCtors() { + // Get the type of @llvm.global_ctors + std::vector CtorFields; + CtorFields.push_back(llvm::IntegerType::get(32)); + // Constructor function type + std::vector VoidArgs; + llvm::FunctionType* CtorFuncTy = llvm::FunctionType::get( + llvm::Type::VoidTy, + VoidArgs, + false); + // i32, function type pair + CtorFields.push_back(llvm::PointerType::getUnqual(CtorFuncTy)); + llvm::StructType* CtorStructTy = llvm::StructType::get(CtorFields, false); + // Array of fields + llvm::ArrayType* GlobalCtorsTy = llvm::ArrayType::get(CtorStructTy, + GlobalCtors.size()); + + const std::string GlobalCtorsVar = std::string("llvm.global_ctors"); + // Define the global variable + llvm::GlobalVariable *GlobalCtorsVal = new llvm::GlobalVariable( + GlobalCtorsTy, + false, + llvm::GlobalValue::AppendingLinkage, + (llvm::Constant*)0, + GlobalCtorsVar, + &TheModule); + + // Populate the array + std::vector CtorValues; + llvm::Constant *MagicNumber = llvm::ConstantInt::get(llvm::IntegerType::Int32Ty, + 65535, + false); + for (std::vector::iterator I = GlobalCtors.begin(), + E = GlobalCtors.end(); I != E; ++I) { + std::vector StructValues; + StructValues.push_back(MagicNumber); + StructValues.push_back(*I); + + llvm::Constant* CtorEntry = llvm::ConstantStruct::get(CtorStructTy, StructValues); + CtorValues.push_back(CtorEntry); + } + llvm::Constant* CtorArray = llvm::ConstantArray::get(GlobalCtorsTy, CtorValues); + GlobalCtorsVal->setInitializer(CtorArray); + +} + +/// ReplaceMapValuesWith - This is a really slow and bad function that +/// searches for any entries in GlobalDeclMap that point to OldVal, changing +/// them to point to NewVal. This is badbadbad, FIXME! +void CodeGenModule::ReplaceMapValuesWith(llvm::Constant *OldVal, + llvm::Constant *NewVal) { + for (llvm::DenseMap::iterator + I = GlobalDeclMap.begin(), E = GlobalDeclMap.end(); I != E; ++I) + if (I->second == OldVal) I->second = NewVal; +} + + +llvm::Constant *CodeGenModule::GetAddrOfFunctionDecl(const FunctionDecl *D, + bool isDefinition) { + // See if it is already in the map. If so, just return it. + llvm::Constant *&Entry = GlobalDeclMap[D]; + if (Entry) return Entry; + + const llvm::Type *Ty = getTypes().ConvertType(D->getType()); + + // Check to see if the function already exists. + llvm::Function *F = getModule().getFunction(D->getName()); + const llvm::FunctionType *FTy = cast(Ty); + + // If it doesn't already exist, just create and return an entry. + if (F == 0) { + // FIXME: param attributes for sext/zext etc. + F = new llvm::Function(FTy, llvm::Function::ExternalLinkage, D->getName(), + &getModule()); + + // Set the appropriate calling convention for the Function. + if (D->getAttr()) + F->setCallingConv(llvm::CallingConv::Fast); + return Entry = F; + } + + // If the pointer type matches, just return it. + llvm::Type *PFTy = llvm::PointerType::getUnqual(Ty); + if (PFTy == F->getType()) return Entry = F; + + // If this isn't a definition, just return it casted to the right type. + if (!isDefinition) + return Entry = llvm::ConstantExpr::getBitCast(F, PFTy); + + // Otherwise, we have a definition after a prototype with the wrong type. + // F is the Function* for the one with the wrong type, we must make a new + // Function* and update everything that used F (a declaration) with the new + // Function* (which will be a definition). + // + // This happens if there is a prototype for a function (e.g. "int f()") and + // then a definition of a different type (e.g. "int f(int x)"). Start by + // making a new function of the correct type, RAUW, then steal the name. + llvm::Function *NewFn = new llvm::Function(FTy, + llvm::Function::ExternalLinkage, + "", &getModule()); + NewFn->takeName(F); + + // Replace uses of F with the Function we will endow with a body. + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewFn, F->getType()); + F->replaceAllUsesWith(NewPtrForOldDecl); + + // FIXME: Update the globaldeclmap for the previous decl of this name. We + // really want a way to walk all of these, but we don't have it yet. This + // is incredibly slow! + ReplaceMapValuesWith(F, NewPtrForOldDecl); + + // Ok, delete the old function now, which is dead. + assert(F->isDeclaration() && "Shouldn't replace non-declaration"); + F->eraseFromParent(); + + // Return the new function which has the right type. + return Entry = NewFn; +} + +static bool IsZeroElementArray(const llvm::Type *Ty) { + if (const llvm::ArrayType *ATy = dyn_cast(Ty)) + return ATy->getNumElements() == 0; + return false; +} + +llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, + bool isDefinition) { + assert(D->hasGlobalStorage() && "Not a global variable"); + + // See if it is already in the map. + llvm::Constant *&Entry = GlobalDeclMap[D]; + if (Entry) return Entry; + + QualType ASTTy = D->getType(); + const llvm::Type *Ty = getTypes().ConvertTypeForMem(ASTTy); + + // Check to see if the global already exists. + llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName(), true); + + // If it doesn't already exist, just create and return an entry. + if (GV == 0) { + return Entry = new llvm::GlobalVariable(Ty, false, + llvm::GlobalValue::ExternalLinkage, + 0, D->getName(), &getModule(), 0, + ASTTy.getAddressSpace()); + } + + // If the pointer type matches, just return it. + llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); + if (PTy == GV->getType()) return Entry = GV; + + // If this isn't a definition, just return it casted to the right type. + if (!isDefinition) + return Entry = llvm::ConstantExpr::getBitCast(GV, PTy); + + + // Otherwise, we have a definition after a prototype with the wrong type. + // GV is the GlobalVariable* for the one with the wrong type, we must make a + /// new GlobalVariable* and update everything that used GV (a declaration) + // with the new GlobalVariable* (which will be a definition). + // + // This happens if there is a prototype for a global (e.g. "extern int x[];") + // and then a definition of a different type (e.g. "int x[10];"). Start by + // making a new global of the correct type, RAUW, then steal the name. + llvm::GlobalVariable *NewGV = + new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, + 0, D->getName(), &getModule(), 0, + ASTTy.getAddressSpace()); + NewGV->takeName(GV); + + // Replace uses of GV with the globalvalue we will endow with a body. + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewGV, GV->getType()); + GV->replaceAllUsesWith(NewPtrForOldDecl); + + // FIXME: Update the globaldeclmap for the previous decl of this name. We + // really want a way to walk all of these, but we don't have it yet. This + // is incredibly slow! + ReplaceMapValuesWith(GV, NewPtrForOldDecl); + + // Verify that GV was a declaration or something like x[] which turns into + // [0 x type]. + assert((GV->isDeclaration() || + IsZeroElementArray(GV->getType()->getElementType())) && + "Shouldn't replace non-declaration"); + + // Ok, delete the old global now, which is dead. + GV->eraseFromParent(); + + // Return the new global which has the right type. + return Entry = NewGV; +} + + +void CodeGenModule::EmitFunction(const FunctionDecl *FD) { + // If this is not a prototype, emit the body. + if (FD->getBody()) + CodeGenFunction(*this).GenerateCode(FD); +} + +llvm::Constant *CodeGenModule::EmitGlobalInit(const Expr *Expr) { + return EmitConstantExpr(Expr); +} + +void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) { + // If this is just a forward declaration of the variable, don't emit it now, + // allow it to be emitted lazily on its first use. + if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0) + return; + + // Get the global, forcing it to be a direct reference. + llvm::GlobalVariable *GV = + cast(GetAddrOfGlobalVar(D, true)); + + // Convert the initializer, or use zero if appropriate. + llvm::Constant *Init = 0; + if (D->getInit() == 0) { + Init = llvm::Constant::getNullValue(GV->getType()->getElementType()); + } else if (D->getType()->isIntegerType()) { + llvm::APSInt Value(static_cast( + getContext().getTypeSize(D->getInit()->getType()))); + if (D->getInit()->isIntegerConstantExpr(Value, Context)) + Init = llvm::ConstantInt::get(Value); + } + + if (!Init) + Init = EmitGlobalInit(D->getInit()); + + assert(GV->getType()->getElementType() == Init->getType() && + "Initializer codegen type mismatch!"); + GV->setInitializer(Init); + + if (const VisibilityAttr *attr = D->getAttr()) + GV->setVisibility(attr->getVisibility()); + // FIXME: else handle -fvisibility + + // Set the llvm linkage type as appropriate. + if (D->getAttr()) + GV->setLinkage(llvm::Function::DLLImportLinkage); + else if (D->getAttr()) + GV->setLinkage(llvm::Function::DLLExportLinkage); + else if (D->getAttr()) { + GV->setLinkage(llvm::GlobalVariable::WeakLinkage); + + } else { + // FIXME: This isn't right. This should handle common linkage and other + // stuff. + switch (D->getStorageClass()) { + case VarDecl::Auto: + case VarDecl::Register: + assert(0 && "Can't have auto or register globals"); + case VarDecl::None: + if (!D->getInit()) + GV->setLinkage(llvm::GlobalVariable::WeakLinkage); + break; + case VarDecl::Extern: + case VarDecl::PrivateExtern: + // todo: common + break; + case VarDecl::Static: + GV->setLinkage(llvm::GlobalVariable::InternalLinkage); + break; + } + } +} + +/// EmitGlobalVarDeclarator - Emit all the global vars attached to the specified +/// declarator chain. +void CodeGenModule::EmitGlobalVarDeclarator(const FileVarDecl *D) { + for (; D; D = cast_or_null(D->getNextDeclarator())) + EmitGlobalVar(D); +} + +void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { + // Make sure that this type is translated. + Types.UpdateCompletedType(TD); +} + + +/// getBuiltinLibFunction +llvm::Function *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) { + if (BuiltinID > BuiltinFunctions.size()) + BuiltinFunctions.resize(BuiltinID); + + // Cache looked up functions. Since builtin id #0 is invalid we don't reserve + // a slot for it. + assert(BuiltinID && "Invalid Builtin ID"); + llvm::Function *&FunctionSlot = BuiltinFunctions[BuiltinID-1]; + if (FunctionSlot) + return FunctionSlot; + + assert(Context.BuiltinInfo.isLibFunction(BuiltinID) && "isn't a lib fn"); + + // Get the name, skip over the __builtin_ prefix. + const char *Name = Context.BuiltinInfo.GetName(BuiltinID)+10; + + // Get the type for the builtin. + QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context); + const llvm::FunctionType *Ty = + cast(getTypes().ConvertType(Type)); + + // FIXME: This has a serious problem with code like this: + // void abs() {} + // ... __builtin_abs(x); + // The two versions of abs will collide. The fix is for the builtin to win, + // and for the existing one to be turned into a constantexpr cast of the + // builtin. In the case where the existing one is a static function, it + // should just be renamed. + if (llvm::Function *Existing = getModule().getFunction(Name)) { + if (Existing->getFunctionType() == Ty && Existing->hasExternalLinkage()) + return FunctionSlot = Existing; + assert(Existing == 0 && "FIXME: Name collision"); + } + + // FIXME: param attributes for sext/zext etc. + return FunctionSlot = new llvm::Function(Ty, llvm::Function::ExternalLinkage, + Name, &getModule()); +} + +llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys, + unsigned NumTys) { + return llvm::Intrinsic::getDeclaration(&getModule(), + (llvm::Intrinsic::ID)IID, Tys, NumTys); +} + +llvm::Function *CodeGenModule::getMemCpyFn() { + if (MemCpyFn) return MemCpyFn; + llvm::Intrinsic::ID IID; + switch (Context.Target.getPointerWidth(0)) { + default: assert(0 && "Unknown ptr width"); + case 32: IID = llvm::Intrinsic::memcpy_i32; break; + case 64: IID = llvm::Intrinsic::memcpy_i64; break; + } + return MemCpyFn = getIntrinsic(IID); +} + +llvm::Function *CodeGenModule::getMemSetFn() { + if (MemSetFn) return MemSetFn; + llvm::Intrinsic::ID IID; + switch (Context.Target.getPointerWidth(0)) { + default: assert(0 && "Unknown ptr width"); + case 32: IID = llvm::Intrinsic::memset_i32; break; + case 64: IID = llvm::Intrinsic::memset_i64; break; + } + return MemSetFn = getIntrinsic(IID); +} + +llvm::Constant *CodeGenModule:: +GetAddrOfConstantCFString(const std::string &str) { + llvm::StringMapEntry &Entry = + CFConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); + + if (Entry.getValue()) + return Entry.getValue(); + + std::vector Fields; + + if (!CFConstantStringClassRef) { + const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + Ty = llvm::ArrayType::get(Ty, 0); + + CFConstantStringClassRef = + new llvm::GlobalVariable(Ty, false, + llvm::GlobalVariable::ExternalLinkage, 0, + "__CFConstantStringClassReference", + &getModule()); + } + + // Class pointer. + llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); + llvm::Constant *Zeros[] = { Zero, Zero }; + llvm::Constant *C = + llvm::ConstantExpr::getGetElementPtr(CFConstantStringClassRef, Zeros, 2); + Fields.push_back(C); + + // Flags. + const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + Fields.push_back(llvm::ConstantInt::get(Ty, 1992)); + + // String pointer. + C = llvm::ConstantArray::get(str); + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, ".str", &getModule()); + + C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2); + Fields.push_back(C); + + // String length. + Ty = getTypes().ConvertType(getContext().LongTy); + Fields.push_back(llvm::ConstantInt::get(Ty, str.length())); + + // The struct. + Ty = getTypes().ConvertType(getContext().getCFConstantStringType()); + C = llvm::ConstantStruct::get(cast(Ty), Fields); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalVariable::InternalLinkage, + C, "", &getModule()); + GV->setSection("__DATA,__cfstring"); + Entry.setValue(GV); + return GV; +} + +/// GenerateWritableString -- Creates storage for a string literal. +static llvm::Constant *GenerateStringLiteral(const std::string &str, + bool constant, + CodeGenModule &CGM) { + // Create Constant for this string literal + llvm::Constant *C=llvm::ConstantArray::get(str); + + // Create a global variable for this string + C = new llvm::GlobalVariable(C->getType(), constant, + llvm::GlobalValue::InternalLinkage, + C, ".str", &CGM.getModule()); + return C; +} + +/// CodeGenModule::GetAddrOfConstantString -- returns a pointer to the character +/// array containing the literal. The result is pointer to array type. +llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str) { + // Don't share any string literals if writable-strings is turned on. + if (Features.WritableStrings) + return GenerateStringLiteral(str, false, *this); + + llvm::StringMapEntry &Entry = + ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); + + if (Entry.getValue()) + return Entry.getValue(); + + // Create a global variable for this. + llvm::Constant *C = GenerateStringLiteral(str, true, *this); + Entry.setValue(C); + return C; +} diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h new file mode 100644 index 00000000000..cbea09fd3ec --- /dev/null +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -0,0 +1,129 @@ +//===--- CodeGenModule.h - Per-Module state for LLVM CodeGen --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the internal per-translation-unit state used for llvm translation. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CODEGENMODULE_H +#define CLANG_CODEGEN_CODEGENMODULE_H + +#include "CodeGenTypes.h" +#include "CGObjCRuntime.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" + +namespace llvm { + class Module; + class Constant; + class Function; + class GlobalVariable; + class TargetData; +} + +namespace clang { + class ASTContext; + class FunctionDecl; + class Decl; + class Expr; + class Stmt; + class ValueDecl; + class VarDecl; + class TypeDecl; + class FileVarDecl; + struct LangOptions; + class Diagnostic; + +namespace CodeGen { + + class CodeGenFunction; + +/// CodeGenModule - This class organizes the cross-module state that is used +/// while generating LLVM code. +class CodeGenModule { + ASTContext &Context; + const LangOptions &Features; + llvm::Module &TheModule; + const llvm::TargetData &TheTargetData; + Diagnostic &Diags; + CodeGenTypes Types; + CGObjCRuntime *Runtime; + + llvm::Function *MemCpyFn; + llvm::Function *MemSetFn; + llvm::DenseMap GlobalDeclMap; + std::vector GlobalCtors; + + llvm::StringMap CFConstantStringMap; + llvm::StringMap ConstantStringMap; + llvm::Constant *CFConstantStringClassRef; + + std::vector BuiltinFunctions; +public: + CodeGenModule(ASTContext &C, const LangOptions &Features, llvm::Module &M, + const llvm::TargetData &TD, Diagnostic &Diags); + ~CodeGenModule(); + + CGObjCRuntime *getObjCRuntime() { return Runtime; } + ASTContext &getContext() const { return Context; } + const LangOptions &getLangOptions() const { return Features; } + llvm::Module &getModule() const { return TheModule; } + CodeGenTypes &getTypes() { return Types; } + Diagnostic &getDiags() const { return Diags; } + const llvm::TargetData &getTargetData() const { return TheTargetData; } + + llvm::Constant *GetAddrOfFunctionDecl(const FunctionDecl *D, + bool isDefinition); + llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, bool isDefinition); + + + /// getBuiltinLibFunction - Given a builtin id for a function like + /// "__builtin_fabsf", return a Function* for "fabsf". + /// + llvm::Function *getBuiltinLibFunction(unsigned BuiltinID); + llvm::Constant *GetAddrOfConstantCFString(const std::string& str); + + /// GetAddrOfConstantString -- returns a pointer to the character + /// array containing the literal. The result is pointer to array type. + llvm::Constant *GetAddrOfConstantString(const std::string& str); + llvm::Function *getMemCpyFn(); + llvm::Function *getMemSetFn(); + llvm::Function *getIntrinsic(unsigned IID, const llvm::Type **Tys = 0, + unsigned NumTys = 0); + + void AddGlobalCtor(llvm::Function * Ctor); + void EmitGlobalCtors(void); + + void EmitFunction(const FunctionDecl *FD); + void EmitGlobalVar(const FileVarDecl *D); + void EmitGlobalVarDeclarator(const FileVarDecl *D); + void UpdateCompletedType(const TagDecl *D); + llvm::Constant *EmitGlobalInit(const Expr *E); + llvm::Constant *EmitConstantExpr(const Expr *E, CodeGenFunction *CGF = 0); + + /// WarnUnsupported - Print out a warning that codegen doesn't support the + /// specified stmt yet. + + void WarnUnsupported(const Stmt *S, const char *Type); + + /// WarnUnsupported - Print out a warning that codegen doesn't support the + /// specified decl yet. + void WarnUnsupported(const Decl *D, const char *Type); + +private: + /// ReplaceMapValuesWith - This is a really slow and bad function that + /// searches for any entries in GlobalDeclMap that point to OldVal, changing + /// them to point to NewVal. This is badbadbad, FIXME! + void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal); + +}; +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp new file mode 100644 index 00000000000..9a669e87056 --- /dev/null +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -0,0 +1,580 @@ +//===--- CodeGenTypes.cpp - Type translation for LLVM CodeGen -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the code that handles AST -> LLVM type lowering. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenTypes.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/AST/AST.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetData.h" + +using namespace clang; +using namespace CodeGen; + +namespace { + /// RecordOrganizer - This helper class, used by CGRecordLayout, layouts + /// structs and unions. It manages transient information used during layout. + /// FIXME : Handle field aligments. Handle packed structs. + class RecordOrganizer { + public: + explicit RecordOrganizer(CodeGenTypes &Types) : + CGT(Types), STy(NULL), llvmFieldNo(0), Cursor(0), + llvmSize(0) {} + + /// addField - Add new field. + void addField(const FieldDecl *FD); + + /// addLLVMField - Add llvm struct field that corresponds to llvm type Ty. + /// Increment field count. + void addLLVMField(const llvm::Type *Ty, bool isPaddingField = false); + + /// addPaddingFields - Current cursor is not suitable place to add next + /// field. Add required padding fields. + void addPaddingFields(unsigned WaterMark); + + /// layoutStructFields - Do the actual work and lay out all fields. Create + /// corresponding llvm struct type. This should be invoked only after + /// all fields are added. + void layoutStructFields(const ASTRecordLayout &RL); + + /// layoutUnionFields - Do the actual work and lay out all fields. Create + /// corresponding llvm struct type. This should be invoked only after + /// all fields are added. + void layoutUnionFields(); + + /// getLLVMType - Return associated llvm struct type. This may be NULL + /// if fields are not laid out. + llvm::Type *getLLVMType() const { + return STy; + } + + /// placeBitField - Find a place for FD, which is a bit-field. + void placeBitField(const FieldDecl *FD); + + llvm::SmallSet &getPaddingFields() { + return PaddingFields; + } + + private: + CodeGenTypes &CGT; + llvm::Type *STy; + unsigned llvmFieldNo; + uint64_t Cursor; + uint64_t llvmSize; + llvm::SmallVector FieldDecls; + std::vector LLVMFields; + llvm::SmallSet PaddingFields; + }; +} + +CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, + const llvm::TargetData &TD) + : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD) { +} + +CodeGenTypes::~CodeGenTypes() { + for(llvm::DenseMap::iterator + I = CGRecordLayouts.begin(), E = CGRecordLayouts.end(); + I != E; ++I) + delete I->second; + CGRecordLayouts.clear(); +} + +/// ConvertType - Convert the specified type to its LLVM form. +const llvm::Type *CodeGenTypes::ConvertType(QualType T) { + // See if type is already cached. + llvm::DenseMap::iterator + I = TypeCache.find(T.getCanonicalType().getTypePtr()); + // If type is found in map and this is not a definition for a opaque + // place holder type then use it. Otherwise, convert type T. + if (I != TypeCache.end()) + return I->second.get(); + + const llvm::Type *ResultType = ConvertNewType(T); + TypeCache.insert(std::make_pair(T.getCanonicalType().getTypePtr(), + llvm::PATypeHolder(ResultType))); + return ResultType; +} + +/// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from +/// ConvertType in that it is used to convert to the memory representation for +/// a type. For example, the scalar representation for _Bool is i1, but the +/// memory representation is usually i8 or i32, depending on the target. +const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { + const llvm::Type *R = ConvertType(T); + + // If this is a non-bool type, don't map it. + if (R != llvm::Type::Int1Ty) + return R; + + // Otherwise, return an integer of the target-specified size. + return llvm::IntegerType::get((unsigned)Context.getTypeSize(T)); + +} + +/// UpdateCompletedType - When we find the full definition for a TagDecl, +/// replace the 'opaque' type we previously made for it if applicable. +void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { + llvm::DenseMap::iterator TDTI = + TagDeclTypes.find(TD); + if (TDTI == TagDeclTypes.end()) return; + + // Remember the opaque LLVM type for this tagdecl. + llvm::PATypeHolder OpaqueHolder = TDTI->second; + assert(isa(OpaqueHolder.get()) && + "Updating compilation of an already non-opaque type?"); + + // Remove it from TagDeclTypes so that it will be regenerated. + TagDeclTypes.erase(TDTI); + + // Generate the new type. + const llvm::Type *NT = ConvertTagDeclType(TD); + + // Refine the old opaque type to its new definition. + cast(OpaqueHolder.get())->refineAbstractTypeTo(NT); +} + + + +const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { + const clang::Type &Ty = *T.getCanonicalType(); + + switch (Ty.getTypeClass()) { + case Type::TypeName: // typedef isn't canonical. + case Type::TypeOfExp: // typeof isn't canonical. + case Type::TypeOfTyp: // typeof isn't canonical. + assert(0 && "Non-canonical type, shouldn't happen"); + case Type::Builtin: { + switch (cast(Ty).getKind()) { + case BuiltinType::Void: + // LLVM void type can only be used as the result of a function call. Just + // map to the same as char. + return llvm::IntegerType::get(8); + + case BuiltinType::Bool: + // Note that we always return bool as i1 for use as a scalar type. + return llvm::Type::Int1Ty; + + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Int: + case BuiltinType::UInt: + case BuiltinType::Long: + case BuiltinType::ULong: + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + return llvm::IntegerType::get( + static_cast(Context.getTypeSize(T))); + + case BuiltinType::Float: return llvm::Type::FloatTy; + case BuiltinType::Double: return llvm::Type::DoubleTy; + case BuiltinType::LongDouble: + // FIXME: mapping long double onto double. + return llvm::Type::DoubleTy; + } + break; + } + case Type::Complex: { + std::vector Elts; + Elts.push_back(ConvertType(cast(Ty).getElementType())); + Elts.push_back(Elts[0]); + return llvm::StructType::get(Elts); + } + case Type::Pointer: { + const PointerType &P = cast(Ty); + QualType ETy = P.getPointeeType(); + return llvm::PointerType::get(ConvertType(ETy), ETy.getAddressSpace()); + } + case Type::Reference: { + const ReferenceType &R = cast(Ty); + return llvm::PointerType::getUnqual(ConvertType(R.getReferenceeType())); + } + + case Type::VariableArray: { + const VariableArrayType &A = cast(Ty); + assert(A.getIndexTypeQualifier() == 0 && + "FIXME: We only handle trivial array types so far!"); + // VLAs resolve to the innermost element type; this matches + // the return of alloca, and there isn't any obviously better choice. + return ConvertType(A.getElementType()); + } + case Type::IncompleteArray: { + const IncompleteArrayType &A = cast(Ty); + assert(A.getIndexTypeQualifier() == 0 && + "FIXME: We only handle trivial array types so far!"); + // int X[] -> [0 x int] + return llvm::ArrayType::get(ConvertType(A.getElementType()), 0); + } + case Type::ConstantArray: { + const ConstantArrayType &A = cast(Ty); + const llvm::Type *EltTy = ConvertType(A.getElementType()); + return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue()); + } + case Type::OCUVector: + case Type::Vector: { + const VectorType &VT = cast(Ty); + return llvm::VectorType::get(ConvertType(VT.getElementType()), + VT.getNumElements()); + } + case Type::FunctionNoProto: + case Type::FunctionProto: { + const FunctionType &FP = cast(Ty); + const llvm::Type *ResultType; + + if (FP.getResultType()->isVoidType()) + ResultType = llvm::Type::VoidTy; // Result of function uses llvm void. + else + ResultType = ConvertType(FP.getResultType()); + + // FIXME: Convert argument types. + bool isVarArg; + std::vector ArgTys; + + // Struct return passes the struct byref. + if (!ResultType->isFirstClassType() && ResultType != llvm::Type::VoidTy) { + ArgTys.push_back(llvm::PointerType::get(ResultType, + FP.getResultType().getAddressSpace())); + ResultType = llvm::Type::VoidTy; + } + + if (const FunctionTypeProto *FTP = dyn_cast(&FP)) { + DecodeArgumentTypes(*FTP, ArgTys); + isVarArg = FTP->isVariadic(); + } else { + isVarArg = true; + } + + return llvm::FunctionType::get(ResultType, ArgTys, isVarArg); + } + + case Type::ASQual: + return ConvertType(QualType(cast(Ty).getBaseType(), 0)); + + case Type::ObjCInterface: + assert(0 && "FIXME: add missing functionality here"); + break; + + case Type::ObjCQualifiedInterface: + assert(0 && "FIXME: add missing functionality here"); + break; + + case Type::ObjCQualifiedId: + assert(0 && "FIXME: add missing functionality here"); + break; + + case Type::Tagged: { + const TagDecl *TD = cast(Ty).getDecl(); + const llvm::Type *Res = ConvertTagDeclType(TD); + + std::string TypeName(TD->getKindName()); + TypeName += '.'; + + // Name the codegen type after the typedef name + // if there is no tag type name available + if (TD->getIdentifier()) + TypeName += TD->getName(); + else if (const TypedefType *TdT = dyn_cast(T)) + TypeName += TdT->getDecl()->getName(); + else + TypeName += "anon"; + + TheModule.addTypeName(TypeName, Res); + return Res; + } + } + + // FIXME: implement. + return llvm::OpaqueType::get(); +} + +void CodeGenTypes::DecodeArgumentTypes(const FunctionTypeProto &FTP, + std::vector &ArgTys) { + for (unsigned i = 0, e = FTP.getNumArgs(); i != e; ++i) { + const llvm::Type *Ty = ConvertType(FTP.getArgType(i)); + if (Ty->isFirstClassType()) + ArgTys.push_back(Ty); + else + // byval arguments are always on the stack, which is addr space #0. + ArgTys.push_back(llvm::PointerType::getUnqual(Ty)); + } +} + +/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or +/// enum. +const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { + llvm::DenseMap::iterator TDTI = + TagDeclTypes.find(TD); + + // If we've already compiled this tag type, use the previous definition. + if (TDTI != TagDeclTypes.end()) + return TDTI->second; + + // If this is still a forward definition, just define an opaque type to use + // for this tagged decl. + if (!TD->isDefinition()) { + llvm::Type *ResultType = llvm::OpaqueType::get(); + TagDeclTypes.insert(std::make_pair(TD, ResultType)); + return ResultType; + } + + // Okay, this is a definition of a type. Compile the implementation now. + + if (TD->getKind() == Decl::Enum) { + // Don't bother storing enums in TagDeclTypes. + return ConvertType(cast(TD)->getIntegerType()); + } + + // This decl could well be recursive. In this case, insert an opaque + // definition of this type, which the recursive uses will get. We will then + // refine this opaque version later. + + // Create new OpaqueType now for later use in case this is a recursive + // type. This will later be refined to the actual type. + llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(); + TagDeclTypes.insert(std::make_pair(TD, ResultHolder)); + + const llvm::Type *ResultType; + const RecordDecl *RD = cast(TD); + if (TD->getKind() == Decl::Struct || TD->getKind() == Decl::Class) { + // Layout fields. + RecordOrganizer RO(*this); + for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i) + RO.addField(RD->getMember(i)); + + RO.layoutStructFields(Context.getASTRecordLayout(RD)); + + // Get llvm::StructType. + CGRecordLayouts[TD] = new CGRecordLayout(RO.getLLVMType(), + RO.getPaddingFields()); + ResultType = RO.getLLVMType(); + + } else if (TD->getKind() == Decl::Union) { + // Just use the largest element of the union, breaking ties with the + // highest aligned member. + if (RD->getNumMembers() != 0) { + RecordOrganizer RO(*this); + for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i) + RO.addField(RD->getMember(i)); + + RO.layoutUnionFields(); + + // Get llvm::StructType. + CGRecordLayouts[TD] = new CGRecordLayout(RO.getLLVMType(), + RO.getPaddingFields()); + ResultType = RO.getLLVMType(); + } else { + ResultType = llvm::StructType::get(std::vector()); + } + } else { + assert(0 && "FIXME: Unknown tag decl kind!"); + } + + // Refine our Opaque type to ResultType. This can invalidate ResultType, so + // make sure to read the result out of the holder. + cast(ResultHolder.get()) + ->refineAbstractTypeTo(ResultType); + + return ResultHolder.get(); +} + +/// getLLVMFieldNo - Return llvm::StructType element number +/// that corresponds to the field FD. +unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) { + llvm::DenseMap::iterator + I = FieldInfo.find(FD); + assert (I != FieldInfo.end() && "Unable to find field info"); + return I->second; +} + +/// addFieldInfo - Assign field number to field FD. +void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No) { + FieldInfo[FD] = No; +} + +/// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field FD. +CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) { + llvm::DenseMap::iterator + I = BitFields.find(FD); + assert (I != BitFields.end() && "Unable to find bitfield info"); + return I->second; +} + +/// addBitFieldInfo - Assign a start bit and a size to field FD. +void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned Begin, + unsigned Size) { + BitFields.insert(std::make_pair(FD, BitFieldInfo(Begin, Size))); +} + +/// getCGRecordLayout - Return record layout info for the given llvm::Type. +const CGRecordLayout * +CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const { + llvm::DenseMap::iterator I + = CGRecordLayouts.find(TD); + assert (I != CGRecordLayouts.end() + && "Unable to find record layout information for type"); + return I->second; +} + +/// addField - Add new field. +void RecordOrganizer::addField(const FieldDecl *FD) { + assert (!STy && "Record fields are already laid out"); + FieldDecls.push_back(FD); +} + +/// layoutStructFields - Do the actual work and lay out all fields. Create +/// corresponding llvm struct type. This should be invoked only after +/// all fields are added. +/// FIXME : At the moment assume +/// - one to one mapping between AST FieldDecls and +/// llvm::StructType elements. +/// - Ignore bit fields +/// - Ignore field aligments +/// - Ignore packed structs +void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { + // FIXME : Use SmallVector + llvmSize = 0; + llvmFieldNo = 0; + Cursor = 0; + LLVMFields.clear(); + + for (llvm::SmallVector::iterator I = FieldDecls.begin(), + E = FieldDecls.end(); I != E; ++I) { + const FieldDecl *FD = *I; + + if (FD->isBitField()) + placeBitField(FD); + else { + const llvm::Type *Ty = CGT.ConvertType(FD->getType()); + addLLVMField(Ty); + CGT.addFieldInfo(FD, llvmFieldNo - 1); + Cursor = llvmSize; + } + } + + unsigned StructAlign = RL.getAlignment(); + if (llvmSize % StructAlign) { + unsigned StructPadding = StructAlign - (llvmSize % StructAlign); + addPaddingFields(llvmSize + StructPadding); + } + + STy = llvm::StructType::get(LLVMFields); +} + +/// addPaddingFields - Current cursor is not suitable place to add next field. +/// Add required padding fields. +void RecordOrganizer::addPaddingFields(unsigned WaterMark) { + assert(WaterMark >= llvmSize && "Invalid padding Field"); + unsigned RequiredBits = WaterMark - llvmSize; + unsigned RequiredBytes = (RequiredBits + 7) / 8; + for (unsigned i = 0; i != RequiredBytes; ++i) + addLLVMField(llvm::Type::Int8Ty, true); +} + +/// addLLVMField - Add llvm struct field that corresponds to llvm type Ty. +/// Increment field count. +void RecordOrganizer::addLLVMField(const llvm::Type *Ty, bool isPaddingField) { + + unsigned AlignmentInBits = CGT.getTargetData().getABITypeAlignment(Ty) * 8; + if (llvmSize % AlignmentInBits) { + // At the moment, insert padding fields even if target specific llvm + // type alignment enforces implict padding fields for FD. Later on, + // optimize llvm fields by removing implicit padding fields and + // combining consequetive padding fields. + unsigned Padding = AlignmentInBits - (llvmSize % AlignmentInBits); + addPaddingFields(llvmSize + Padding); + } + + unsigned TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); + llvmSize += TySize; + if (isPaddingField) + PaddingFields.insert(llvmFieldNo); + LLVMFields.push_back(Ty); + ++llvmFieldNo; +} + +/// layoutUnionFields - Do the actual work and lay out all fields. Create +/// corresponding llvm struct type. This should be invoked only after +/// all fields are added. +void RecordOrganizer::layoutUnionFields() { + + unsigned PrimaryEltNo = 0; + std::pair PrimaryElt = + CGT.getContext().getTypeInfo(FieldDecls[0]->getType()); + CGT.addFieldInfo(FieldDecls[0], 0); + + unsigned Size = FieldDecls.size(); + for(unsigned i = 1; i != Size; ++i) { + const FieldDecl *FD = FieldDecls[i]; + assert (!FD->isBitField() && "Bit fields are not yet supported"); + std::pair EltInfo = + CGT.getContext().getTypeInfo(FD->getType()); + + // Use largest element, breaking ties with the hightest aligned member. + if (EltInfo.first > PrimaryElt.first || + (EltInfo.first == PrimaryElt.first && + EltInfo.second > PrimaryElt.second)) { + PrimaryElt = EltInfo; + PrimaryEltNo = i; + } + + // In union, each field gets first slot. + CGT.addFieldInfo(FD, 0); + } + + std::vector Fields; + const llvm::Type *Ty = CGT.ConvertType(FieldDecls[PrimaryEltNo]->getType()); + Fields.push_back(Ty); + STy = llvm::StructType::get(Fields); +} + +/// placeBitField - Find a place for FD, which is a bit-field. +/// This function searches for the last aligned field. If the bit-field fits in +/// it, it is reused. Otherwise, the bit-field is placed in a new field. +void RecordOrganizer::placeBitField(const FieldDecl *FD) { + + assert (FD->isBitField() && "FD is not a bit-field"); + Expr *BitWidth = FD->getBitWidth(); + llvm::APSInt FieldSize(32); + bool isBitField = + BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext()); + assert (isBitField && "Invalid BitField size expression"); + uint64_t BitFieldSize = FieldSize.getZExtValue(); + + const llvm::Type *Ty = CGT.ConvertType(FD->getType()); + uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); + + unsigned Idx = Cursor / TySize; + unsigned BitsLeft = TySize - (Cursor % TySize); + + if (BitsLeft >= BitFieldSize) { + // The bitfield fits in the last aligned field. + // This is : struct { char a; int CurrentField:10;}; + // where 'CurrentField' shares first field with 'a'. + CGT.addFieldInfo(FD, Idx); + CGT.addBitFieldInfo(FD, TySize - BitsLeft, BitFieldSize); + Cursor += BitFieldSize; + } else { + // Place the bitfield in a new LLVM field. + // This is : struct { char a; short CurrentField:10;}; + // where 'CurrentField' needs a new llvm field. + CGT.addFieldInfo(FD, Idx + 1); + CGT.addBitFieldInfo(FD, 0, BitFieldSize); + Cursor = (Idx + 1) * TySize + BitFieldSize; + } + if (Cursor > llvmSize) + addPaddingFields(Cursor); +} diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h new file mode 100644 index 00000000000..08a2467106a --- /dev/null +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -0,0 +1,165 @@ +//===--- CodeGenTypes.h - Type translation for LLVM CodeGen -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the code that handles AST -> LLVM type lowering. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CODEGENTYPES_H +#define CLANG_CODEGEN_CODEGENTYPES_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" +#include + +namespace llvm { + class Module; + class Type; + class PATypeHolder; + class TargetData; +} + +namespace clang { + class ASTContext; + class TagDecl; + class TargetInfo; + class QualType; + class Type; + class FunctionTypeProto; + class FieldDecl; + class RecordDecl; + +namespace CodeGen { + class CodeGenTypes; + + /// CGRecordLayout - This class handles struct and union layout info while + /// lowering AST types to LLVM types. + class CGRecordLayout { + CGRecordLayout(); // DO NOT IMPLEMENT + public: + CGRecordLayout(llvm::Type *T, llvm::SmallSet &PF) + : STy(T), PaddingFields(PF) { + // FIXME : Collect info about fields that requires adjustments + // (i.e. fields that do not directly map to llvm struct fields.) + } + + /// getLLVMType - Return llvm type associated with this record. + llvm::Type *getLLVMType() const { + return STy; + } + + bool isPaddingField(unsigned No) const { + return PaddingFields.count(No) != 0; + } + + unsigned getNumPaddingFields() { + return PaddingFields.size(); + } + + private: + llvm::Type *STy; + llvm::SmallSet PaddingFields; + }; + +/// CodeGenTypes - This class organizes the cross-module state that is used +/// while lowering AST types to LLVM types. +class CodeGenTypes { + ASTContext &Context; + TargetInfo &Target; + llvm::Module& TheModule; + const llvm::TargetData& TheTargetData; + + llvm::DenseMap TagDeclTypes; + + /// CGRecordLayouts - This maps llvm struct type with corresponding + /// record layout info. + /// FIXME : If CGRecordLayout is less than 16 bytes then use + /// inline it in the map. + llvm::DenseMap CGRecordLayouts; + + /// FieldInfo - This maps struct field with corresponding llvm struct type + /// field no. This info is populated by record organizer. + llvm::DenseMap FieldInfo; + +public: + class BitFieldInfo { + public: + explicit BitFieldInfo(unsigned short B, unsigned short S) + : Begin(B), Size(S) {} + + unsigned short Begin; + unsigned short Size; + }; + +private: + llvm::DenseMap BitFields; + + /// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder) + /// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is + /// used instead of llvm::Type because it allows us to bypass potential + /// dangling type pointers due to type refinement on llvm side. + llvm::DenseMap TypeCache; + + /// ConvertNewType - Convert type T into a llvm::Type. Do not use this + /// method directly because it does not do any type caching. This method + /// is available only for ConvertType(). CovertType() is preferred + /// interface to convert type T into a llvm::Type. + const llvm::Type *ConvertNewType(QualType T); +public: + CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD); + ~CodeGenTypes(); + + const llvm::TargetData &getTargetData() const { return TheTargetData; } + TargetInfo &getTarget() const { return Target; } + ASTContext &getContext() const { return Context; } + + /// ConvertType - Convert type T into a llvm::Type. + const llvm::Type *ConvertType(QualType T); + + /// ConvertTypeForMem - Convert type T into a llvm::Type. This differs from + /// ConvertType in that it is used to convert to the memory representation for + /// a type. For example, the scalar representation for _Bool is i1, but the + /// memory representation is usually i8 or i32, depending on the target. + const llvm::Type *ConvertTypeForMem(QualType T); + + + const CGRecordLayout *getCGRecordLayout(const TagDecl*) const; + + /// getLLVMFieldNo - Return llvm::StructType element number + /// that corresponds to the field FD. + unsigned getLLVMFieldNo(const FieldDecl *FD); + + + /// UpdateCompletedType - When we find the full definition for a TagDecl, + /// replace the 'opaque' type we previously made for it if applicable. + void UpdateCompletedType(const TagDecl *TD); + +public: // These are internal details of CGT that shouldn't be used externally. + void DecodeArgumentTypes(const FunctionTypeProto &FTP, + std::vector &ArgTys); + + /// addFieldInfo - Assign field number to field FD. + void addFieldInfo(const FieldDecl *FD, unsigned No); + + /// addBitFieldInfo - Assign a start bit and a size to field FD. + void addBitFieldInfo(const FieldDecl *FD, unsigned Begin, unsigned Size); + + /// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field + /// FD. + BitFieldInfo getBitFieldInfo(const FieldDecl *FD); + + /// ConvertTagDeclType - Lay out a tagged decl type like struct or union or + /// enum. + const llvm::Type *ConvertTagDeclType(const TagDecl *TD); +}; + +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/clang/lib/CodeGen/Makefile b/clang/lib/CodeGen/Makefile new file mode 100644 index 00000000000..4d7828ef67a --- /dev/null +++ b/clang/lib/CodeGen/Makefile @@ -0,0 +1,23 @@ +##===- clang/lib/CodeGen/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the AST -> LLVM code generation library for the +# C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangCodeGen +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp new file mode 100644 index 00000000000..06467488a5e --- /dev/null +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -0,0 +1,104 @@ +//===--- ModuleBuilder.cpp - Emit LLVM Code from ASTs ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This builds an AST and converts it to LLVM Code. +// +//===----------------------------------------------------------------------===// + +#include "clang/CodeGen/ModuleBuilder.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// LLVM Emitter + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" + +namespace { + class CodeGenerator : public ASTConsumer { + Diagnostic &Diags; + const llvm::TargetData *TD; + ASTContext *Ctx; + const LangOptions &Features; + protected: + llvm::Module *&M; + CodeGen::CodeGenModule *Builder; + public: + CodeGenerator(Diagnostic &diags, const LangOptions &LO, + llvm::Module *&DestModule) + : Diags(diags), Features(LO), M(DestModule) {} + + ~CodeGenerator() { + delete Builder; + } + + virtual void Initialize(ASTContext &Context) { + Ctx = &Context; + + M->setTargetTriple(Ctx->Target.getTargetTriple()); + M->setDataLayout(Ctx->Target.getTargetDescription()); + TD = new llvm::TargetData(Ctx->Target.getTargetDescription()); + Builder = new CodeGen::CodeGenModule(Context, Features, *M, *TD, Diags); + } + + virtual void HandleTopLevelDecl(Decl *D) { + // If an error occurred, stop code generation, but continue parsing and + // semantic analysis (to ensure all warnings and errors are emitted). + if (Diags.hasErrorOccurred()) + return; + + if (FunctionDecl *FD = dyn_cast(D)) { + Builder->EmitFunction(FD); + } else if (FileVarDecl *FVD = dyn_cast(D)) { + Builder->EmitGlobalVarDeclarator(FVD); + } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { + if (LSD->getLanguage() == LinkageSpecDecl::lang_cxx) + Builder->WarnUnsupported(LSD, "linkage spec"); + // FIXME: implement C++ linkage, C linkage works mostly by C + // language reuse already. + } else if (FileScopeAsmDecl *AD = dyn_cast(D)) { + std::string AsmString(AD->getAsmString()->getStrData(), + AD->getAsmString()->getByteLength()); + + const std::string &S = Builder->getModule().getModuleInlineAsm(); + if (S.empty()) + Builder->getModule().setModuleInlineAsm(AsmString); + else + Builder->getModule().setModuleInlineAsm(S + '\n' + AsmString); + } else { + assert(isa(D) && "Unknown top level decl"); + // TODO: handle debug info? + } + } + + /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl + /// (e.g. struct, union, enum, class) is completed. This allows the client to + /// hack on the type, which can occur at any point in the file (because these + /// can be defined in declspecs). + virtual void HandleTagDeclDefinition(TagDecl *D) { + Builder->UpdateCompletedType(D); + } + + }; +} + +ASTConsumer *clang::CreateLLVMCodeGen(Diagnostic &Diags, + const LangOptions &Features, + llvm::Module *&DestModule) { + return new CodeGenerator(Diags, Features, DestModule); +} + diff --git a/clang/lib/Headers/Makefile b/clang/lib/Headers/Makefile new file mode 100644 index 00000000000..7af7f0f8700 --- /dev/null +++ b/clang/lib/Headers/Makefile @@ -0,0 +1,39 @@ +##===- clang/lib/Headers/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +include $(LEVEL)/Makefile.common + +HeaderDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/Headers + +HEADERS := $(notdir $(wildcard $(PROJ_SRC_DIR)/*.h)) + +OBJHEADERS := $(addprefix $(HeaderDir)/, $(HEADERS)) + + +$(OBJHEADERS): $(HeaderDir)/%.h: $(PROJ_SRC_DIR)/%.h $(HeaderDir)/.dir + $(Verb) cp $< $@ + @echo Copying $(notdir $<) to build dir + +printit: + echo $(OBJHEADERS) + echo $(PROJ_SRC_DIR) + +# Hook into the standard Makefile rules. +all-local:: $(OBJHEADERS) + +PROJ_headers := $(DESTDIR)$(PROJ_prefix)/Headers + +INSTHEADERS := $(addprefix $(PROJ_headers)/, $(HEADERS)) + +$(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h $(PROJ_headers)/.dir + $(Verb) $(DataInstall) $< $(PROJ_headers) + +install-local:: $(INSTHEADERS) + diff --git a/clang/lib/Headers/mmintrin.devel.h b/clang/lib/Headers/mmintrin.devel.h new file mode 100644 index 00000000000..70cded027ec --- /dev/null +++ b/clang/lib/Headers/mmintrin.devel.h @@ -0,0 +1,377 @@ +/*===---- mmintrin.h - MMX intrinsics --------------------------------------=== + * + * Copyright (c) 2008 Anders Carlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __MMINTRIN_H +#define __MMINTRIN_H + +#ifndef __MMX__ +#error "MMX instruction set not enabled" +#else + +typedef long long __m64 __attribute__((vector_size(8))); + +typedef int __v2si __attribute__((vector_size(8))); +typedef short __v4hi __attribute__((vector_size(8))); +typedef char __v8qi __attribute__((vector_size(8))); + +inline void __attribute__((__always_inline__)) _mm_empty() +{ + __builtin_ia32_emms(); +} + +inline __m64 __attribute__((__always_inline__)) _mm_cvtsi32_si64(int i) +{ + return (__m64)(__v2si){i, 0}; +} + +inline int __attribute__((__always_inline__)) _mm_cvtsi64_si32(__m64 m) +{ + return ((__v2si)m)[0]; +} + +inline __m64 __attribute__((__always_inline__)) _mm_cvtsi64_m64(long long i) +{ + return (__m64)i; +} + +inline long long __attribute__((__always_inline__)) _mm_cvtm64_si64(__m64 m) +{ + return (long long)m; +} + +inline __m64 __attribute__((__always_inline__)) _mm_packs_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_packsswb((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_packs_pi32(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_packssdw((__v2si)m1, (__v2si)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_packs_pu16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_packuswb((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_unpackhi_pi8(__m64 m1, __m64 m2) +{ + // FIXME: use __builtin_shuffle_vector +} + +inline __m64 __attribute__((__always_inline__)) _mm_unpackhi_pi16(__m64 m1, __m64 m2) +{ + // FIXME: use __builtin_shuffle_vector +} + +inline __m64 __attribute__((__always_inline__)) _mm_unpackhi_pi32(__m64 m1, __m64 m2) +{ + // FIXME: use __builtin_shuffle_vector +} + +inline __m64 __attribute__((__always_inline__)) _mm_unpacklo_pi8(__m64 m1, __m64 m2) +{ + // FIXME: use __builtin_shuffle_vector +} + +inline __m64 __attribute__((__always_inline__)) _mm_unpacklo_pi16(__m64 m1, __m64 m2) +{ + // FIXME: use __builtin_shuffle_vector +} + +inline __m64 __attribute__((__always_inline__)) _mm_unpacklo_pi32(__m64 m1, __m64 m2) +{ + // FIXME: use __builtin_shuffle_vector +} + +inline __m64 __attribute__((__always_inline__)) _mm_add_pi8(__m64 m1, __m64 m2) +{ + return (__m64)((__v8qi)m1 + (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_add_pi16(__m64 m1, __m64 m2) +{ + return (__m64)((__v4hi)m1 + (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_add_pi32(__m64 m1, __m64 m2) +{ + return (__m64)((__v2si)m1 + (__v2si)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_adds_pi8(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_paddsb((__v8qi)m1, (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_adds_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_paddsw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_adds_pu8(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_paddusb((__v8qi)m1, (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_adds_pu16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_paddusw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sub_pi8(__m64 m1, __m64 m2) +{ + return (__m64)((__v8qi)m1 - (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sub_pi16(__m64 m1, __m64 m2) +{ + return (__m64)((__v4hi)m1 - (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sub_pi32(__m64 m1, __m64 m2) +{ + return (__m64)((__v2si)m1 - (__v2si)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_subs_pi8(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_psubsb((__v8qi)m1, (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_subs_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_psubsw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_subs_pu8(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_psubusb((__v8qi)m1, (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_subs_pu16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_psubusw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_madd_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pmaddwd((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_mulhi_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pmulhw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_mullo_pi16(__m64 m1, __m64 m2) +{ + return (__m64)((__v4hi)m1 * (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sll_pi16(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_psllw((__v4hi)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_slli_pi16(__m64 m, int count) +{ + return (__m64)__builtin_ia32_psllwi((__v4hi)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sll_pi32(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_pslld((__v2si)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_slli_pi32(__m64 m, int count) +{ + return (__m64)__builtin_ia32_pslldi((__v2si)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sll_pi64(__m64 m, __m64 count) +{ + return __builtin_ia32_psllq(m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_slli_pi64(__m64 m, int count) +{ + return __builtin_ia32_psllqi(m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sra_pi16(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_psraw((__v4hi)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srai_pi16(__m64 m, int count) +{ + return (__m64)__builtin_ia32_psrawi((__v4hi)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_sra_pi32(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_psrad((__v2si)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srai_pi32(__m64 m, int count) +{ + return (__m64)__builtin_ia32_psradi((__v2si)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srl_pi16(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_psrlw((__v4hi)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srli_pi16(__m64 m, int count) +{ + return (__m64)__builtin_ia32_psrlwi((__v4hi)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srl_pi32(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_psrld((__v2si)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srli_pi32(__m64 m, int count) +{ + return (__m64)__builtin_ia32_psrldi((__v2si)m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srl_pi64(__m64 m, __m64 count) +{ + return (__m64)__builtin_ia32_psrlq(m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_srli_pi64(__m64 m, int count) +{ + return __builtin_ia32_psrlqi(m, count); +} + +inline __m64 __attribute__((__always_inline__)) _mm_and_si64(__m64 m1, __m64 m2) +{ + return m1 & m2; +} + +inline __m64 __attribute__((__always_inline__)) _mm_andnot_si64(__m64 m1, __m64 m2) +{ + return ~m1 & m2; +} + +inline __m64 __attribute__((__always_inline__)) _mm_or_si64(__m64 m1, __m64 m2) +{ + return m1 | m2; +} + +inline __m64 __attribute__((__always_inline__)) _mm_xor_si64(__m64 m1, __m64 m2) +{ + return m1 ^ m2; +} + +inline __m64 __attribute__((__always_inline__)) _mm_cmpeq_pi8(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pcmpeqb((__v8qi)m1, (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_cmpeq_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pcmpeqw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_cmpeq_pi32(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pcmpeqd((__v2si)m1, (__v2si)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_cmpgt_pi8(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pcmpgtb((__v8qi)m1, (__v8qi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_cmpgt_pi16(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pcmpgtw((__v4hi)m1, (__v4hi)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_cmpgt_pi32(__m64 m1, __m64 m2) +{ + return (__m64)__builtin_ia32_pcmpgtd((__v2si)m1, (__v2si)m2); +} + +inline __m64 __attribute__((__always_inline__)) _mm_setzero_si64() +{ + return (__m64){ 0LL }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_set_pi32(int i1, int i0) +{ + return (__m64)(__v2si){ i0, i1 }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_set_pi16(short s3, short s2, short s1, short s0) +{ + return (__m64)(__v4hi){ s0, s1, s2, s3 }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_set_pi8(char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0) +{ + return (__m64)(__v8qi){ b0, b1, b2, b3, b4, b5, b6, b7 }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_set1_pi32(int i) +{ + return (__m64)(__v2si){ i, i }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_set1_pi16(short s) +{ + return (__m64)(__v4hi){ s }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_set1_pi8(char b) +{ + return (__m64)(__v8qi){ b }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_setr_pi32(int i1, int i0) +{ + return (__m64)(__v2si){ i1, i0 }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_setr_pi16(short s3, short s2, short s1, short s0) +{ + return (__m64)(__v4hi){ s3, s2, s1, s0 }; +} + +inline __m64 __attribute__((__always_inline__)) _mm_setr_pi8(char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0) +{ + return (__m64)(__v8qi){ b7, b6, b5, b4, b3, b2, b1, b0 }; +} + +#endif /* __MMX__ */ + +#endif /* __MMINTRIN_H */ + diff --git a/clang/lib/Headers/stdbool.h b/clang/lib/Headers/stdbool.h new file mode 100644 index 00000000000..e44a1f9a979 --- /dev/null +++ b/clang/lib/Headers/stdbool.h @@ -0,0 +1,38 @@ +/*===---- stdbool.h - Standard header for booleans -------------------------=== + * + * Copyright (c) 2008 Eli Friedman + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __STDBOOL_H +#define __STDBOOL_H + +/* Don't define bool, true, and false in C++ */ +#ifndef __cplusplus +#define bool _Bool +#define true 1 +#define false 0 +#endif + +#define __bool_true_false_are_defined 1 + +#endif /* __STDBOOL_H */ diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp new file mode 100644 index 00000000000..282e742b4c8 --- /dev/null +++ b/clang/lib/Lex/HeaderMap.cpp @@ -0,0 +1,242 @@ +//===--- HeaderMap.cpp - A file that acts like dir of symlinks ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the HeaderMap interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/HeaderMap.h" +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Data Structures and Manifest Constants +//===----------------------------------------------------------------------===// + +enum { + HMAP_HeaderMagicNumber = ('h' << 24) | ('m' << 16) | ('a' << 8) | 'p', + HMAP_HeaderVersion = 1, + + HMAP_EmptyBucketKey = 0 +}; + +namespace clang { +struct HMapBucket { + uint32_t Key; // Offset (into strings) of key. + + uint32_t Prefix; // Offset (into strings) of value prefix. + uint32_t Suffix; // Offset (into strings) of value suffix. +}; + +struct HMapHeader { + uint32_t Magic; // Magic word, also indicates byte order. + uint16_t Version; // Version number -- currently 1. + uint16_t Reserved; // Reserved for future use - zero for now. + uint32_t StringsOffset; // Offset to start of string pool. + uint32_t NumEntries; // Number of entries in the string table. + uint32_t NumBuckets; // Number of buckets (always a power of 2). + uint32_t MaxValueLength; // Length of longest result path (excluding nul). + // An array of 'NumBuckets' HMapBucket objects follows this header. + // Strings follow the buckets, at StringsOffset. +}; +} // end namespace clang. + +/// HashHMapKey - This is the 'well known' hash function required by the file +/// format, used to look up keys in the hash table. The hash table uses simple +/// linear probing based on this function. +static inline unsigned HashHMapKey(const char *S, const char *End) { + unsigned Result = 0; + + for (; S != End; S++) + Result += tolower(*S) * 13; + return Result; +} + + + +//===----------------------------------------------------------------------===// +// Verification and Construction +//===----------------------------------------------------------------------===// + +/// HeaderMap::Create - This attempts to load the specified file as a header +/// map. If it doesn't look like a HeaderMap, it gives up and returns null. +/// If it looks like a HeaderMap but is obviously corrupted, it puts a reason +/// into the string error argument and returns null. +const HeaderMap *HeaderMap::Create(const FileEntry *FE) { + // If the file is too small to be a header map, ignore it. + unsigned FileSize = FE->getSize(); + if (FileSize <= sizeof(HMapHeader)) return 0; + + llvm::OwningPtr FileBuffer( + llvm::MemoryBuffer::getFile(FE->getName(), strlen(FE->getName()), 0, + FE->getSize())); + if (FileBuffer == 0) return 0; // Unreadable file? + const char *FileStart = FileBuffer->getBufferStart(); + + // We know the file is at least as big as the header, check it now. + const HMapHeader *Header = reinterpret_cast(FileStart); + + // Sniff it to see if it's a headermap by checking the magic number and + // version. + bool NeedsByteSwap; + if (Header->Magic == HMAP_HeaderMagicNumber && + Header->Version == HMAP_HeaderVersion) + NeedsByteSwap = false; + else if (Header->Magic == llvm::ByteSwap_32(HMAP_HeaderMagicNumber) && + Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion)) + NeedsByteSwap = true; // Mixed endianness headermap. + else + return 0; // Not a header map. + + if (Header->Reserved != 0) return 0; + + // Okay, everything looks good, create the header map. + return new HeaderMap(FileBuffer.take(), NeedsByteSwap); +} + +HeaderMap::~HeaderMap() { + delete FileBuffer; +} + +//===----------------------------------------------------------------------===// +// Utility Methods +//===----------------------------------------------------------------------===// + + +/// getFileName - Return the filename of the headermap. +const char *HeaderMap::getFileName() const { + return FileBuffer->getBufferIdentifier(); +} + +unsigned HeaderMap::getEndianAdjustedWord(unsigned X) const { + if (!NeedsBSwap) return X; + return llvm::ByteSwap_32(X); +} + +/// getHeader - Return a reference to the file header, in unbyte-swapped form. +/// This method cannot fail. +const HMapHeader &HeaderMap::getHeader() const { + // We know the file is at least as big as the header. Return it. + return *reinterpret_cast(FileBuffer->getBufferStart()); +} + +/// getBucket - Return the specified hash table bucket from the header map, +/// bswap'ing its fields as appropriate. If the bucket number is not valid, +/// this return a bucket with an empty key (0). +HMapBucket HeaderMap::getBucket(unsigned BucketNo) const { + HMapBucket Result; + Result.Key = HMAP_EmptyBucketKey; + + const HMapBucket *BucketArray = + reinterpret_cast(FileBuffer->getBufferStart() + + sizeof(HMapHeader)); + + const HMapBucket *BucketPtr = BucketArray+BucketNo; + if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) + return Result; // Invalid buffer, corrupt hmap. + + // Otherwise, the bucket is valid. Load the values, bswapping as needed. + Result.Key = getEndianAdjustedWord(BucketPtr->Key); + Result.Prefix = getEndianAdjustedWord(BucketPtr->Prefix); + Result.Suffix = getEndianAdjustedWord(BucketPtr->Suffix); + return Result; +} + +/// getString - Look up the specified string in the string table. If the string +/// index is not valid, it returns an empty string. +const char *HeaderMap::getString(unsigned StrTabIdx) const { + // Add the start of the string table to the idx. + StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset); + + // Check for invalid index. + if (StrTabIdx >= FileBuffer->getBufferSize()) + return 0; + + // Otherwise, we have a valid pointer into the file. Just return it. We know + // that the "string" can not overrun the end of the file, because the buffer + // is nul terminated by virtue of being a MemoryBuffer. + return FileBuffer->getBufferStart()+StrTabIdx; +} + +/// StringsEqualWithoutCase - Compare the specified two strings for case- +/// insensitive equality, returning true if they are equal. Both strings are +/// known to have the same length. +static bool StringsEqualWithoutCase(const char *S1, const char *S2, + unsigned Len) { + for (; Len; ++S1, ++S2, --Len) + if (tolower(*S1) != tolower(*S2)) + return false; + return true; +} + +//===----------------------------------------------------------------------===// +// The Main Drivers +//===----------------------------------------------------------------------===// + +/// dump - Print the contents of this headermap to stderr. +void HeaderMap::dump() const { + const HMapHeader &Hdr = getHeader(); + unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); + + fprintf(stderr, "Header Map %s:\n %d buckets, %d entries\n", + getFileName(), NumBuckets, + getEndianAdjustedWord(Hdr.NumEntries)); + + for (unsigned i = 0; i != NumBuckets; ++i) { + HMapBucket B = getBucket(i); + if (B.Key == HMAP_EmptyBucketKey) continue; + + const char *Key = getString(B.Key); + const char *Prefix = getString(B.Prefix); + const char *Suffix = getString(B.Suffix); + fprintf(stderr, " %d. %s -> '%s' '%s'\n", i, Key, Prefix, Suffix); + } +} + +/// LookupFile - Check to see if the specified relative filename is located in +/// this HeaderMap. If so, open it and return its FileEntry. +const FileEntry *HeaderMap::LookupFile(const char *FilenameStart, + const char *FilenameEnd, + FileManager &FM) const { + const HMapHeader &Hdr = getHeader(); + unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); + + // If the number of buckets is not a power of two, the headermap is corrupt. + // Don't probe infinitely. + if (NumBuckets & (NumBuckets-1)) + return 0; + + // Linearly probe the hash table. + for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) { + HMapBucket B = getBucket(Bucket & (NumBuckets-1)); + if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss. + + // See if the key matches. If not, probe on. + const char *Key = getString(B.Key); + unsigned BucketKeyLen = strlen(Key); + if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart)) + continue; + + // See if the actual strings equal. + if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen)) + continue; + + // If so, we have a match in the hash table. Construct the destination + // path. + llvm::SmallString<1024> DestPath; + DestPath += getString(B.Prefix); + DestPath += getString(B.Suffix); + return FM.getFile(DestPath.begin(), DestPath.end()); + } +} diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp new file mode 100644 index 00000000000..44ae35c8b7e --- /dev/null +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -0,0 +1,425 @@ +//===--- HeaderSearch.cpp - Resolve Header File Locations ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the DirectoryLookup and HeaderSearch interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderMap.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) { + SystemDirIdx = 0; + NoCurDirSearch = false; + + NumIncluded = 0; + NumMultiIncludeFileOptzn = 0; + NumFrameworkLookups = NumSubFrameworkLookups = 0; +} + +HeaderSearch::~HeaderSearch() { + // Delete headermaps. + for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) + delete HeaderMaps[i].second; +} + +void HeaderSearch::PrintStats() { + fprintf(stderr, "\n*** HeaderSearch Stats:\n"); + fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size()); + unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0; + for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) { + NumOnceOnlyFiles += FileInfo[i].isImport; + if (MaxNumIncludes < FileInfo[i].NumIncludes) + MaxNumIncludes = FileInfo[i].NumIncludes; + NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1; + } + fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles); + fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles); + fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes); + + fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded); + fprintf(stderr, " %d #includes skipped due to" + " the multi-include optimization.\n", NumMultiIncludeFileOptzn); + + fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups); + fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups); +} + +/// CreateHeaderMap - This method returns a HeaderMap for the specified +/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. +const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { + // We expect the number of headermaps to be small, and almost always empty. + // If it ever grows, use of a linear search should be re-evaluated. + if (!HeaderMaps.empty()) { + for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) + // Pointer equality comparison of FileEntries works because they are + // already uniqued by inode. + if (HeaderMaps[i].first == FE) + return HeaderMaps[i].second; + } + + if (const HeaderMap *HM = HeaderMap::Create(FE)) { + HeaderMaps.push_back(std::make_pair(FE, HM)); + return HM; + } + + return 0; +} + +//===----------------------------------------------------------------------===// +// File lookup within a DirectoryLookup scope +//===----------------------------------------------------------------------===// + +/// getName - Return the directory or filename corresponding to this lookup +/// object. +const char *DirectoryLookup::getName() const { + if (isNormalDir()) + return getDir()->getName(); + if (isFramework()) + return getFrameworkDir()->getName(); + assert(isHeaderMap() && "Unknown DirectoryLookup"); + return getHeaderMap()->getFileName(); +} + + +/// LookupFile - Lookup the specified file in this search path, returning it +/// if it exists or returning null if not. +const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart, + const char *FilenameEnd, + HeaderSearch &HS) const { + llvm::SmallString<1024> TmpDir; + if (isNormalDir()) { + // Concatenate the requested file onto the directory. + // FIXME: Portability. Filename concatenation should be in sys::Path. + TmpDir += getDir()->getName(); + TmpDir.push_back('/'); + TmpDir.append(FilenameStart, FilenameEnd); + return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end()); + } + + if (isFramework()) + return DoFrameworkLookup(FilenameStart, FilenameEnd, HS); + + assert(isHeaderMap() && "Unknown directory lookup"); + return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr()); +} + + +/// DoFrameworkLookup - Do a lookup of the specified file in the current +/// DirectoryLookup, which is a framework directory. +const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart, + const char *FilenameEnd, + HeaderSearch &HS) const { + FileManager &FileMgr = HS.getFileMgr(); + + // Framework names must have a '/' in the filename. + const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/'); + if (SlashPos == FilenameEnd) return 0; + + // Find out if this is the home for the specified framework, by checking + // HeaderSearch. Possible answer are yes/no and unknown. + const DirectoryEntry *&FrameworkDirCache = + HS.LookupFrameworkCache(FilenameStart, SlashPos); + + // If it is known and in some other directory, fail. + if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir()) + return 0; + + // Otherwise, construct the path to this framework dir. + + // FrameworkName = "/System/Library/Frameworks/" + llvm::SmallString<1024> FrameworkName; + FrameworkName += getFrameworkDir()->getName(); + if (FrameworkName.empty() || FrameworkName.back() != '/') + FrameworkName.push_back('/'); + + // FrameworkName = "/System/Library/Frameworks/Cocoa" + FrameworkName.append(FilenameStart, SlashPos); + + // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" + FrameworkName += ".framework/"; + + // If the cache entry is still unresolved, query to see if the cache entry is + // still unresolved. If so, check its existence now. + if (FrameworkDirCache == 0) { + HS.IncrementFrameworkLookupCount(); + + // If the framework dir doesn't exist, we fail. + // FIXME: It's probably more efficient to query this with FileMgr.getDir. + if (!llvm::sys::Path(std::string(FrameworkName.begin(), + FrameworkName.end())).exists()) + return 0; + + // Otherwise, if it does, remember that this is the right direntry for this + // framework. + FrameworkDirCache = getFrameworkDir(); + } + + // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" + unsigned OrigSize = FrameworkName.size(); + + FrameworkName += "Headers/"; + FrameworkName.append(SlashPos+1, FilenameEnd); + if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(), + FrameworkName.end())) { + return FE; + } + + // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" + const char *Private = "Private"; + FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, + Private+strlen(Private)); + return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end()); +} + + +//===----------------------------------------------------------------------===// +// Header File Location. +//===----------------------------------------------------------------------===// + + +/// LookupFile - Given a "foo" or reference, look up the indicated file, +/// return null on failure. isAngled indicates whether the file reference is +/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if +/// non-null, indicates where the #including file is, in case a relative search +/// is needed. +const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, + const char *FilenameEnd, + bool isAngled, + const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir, + const FileEntry *CurFileEnt) { + // If 'Filename' is absolute, check to see if it exists and no searching. + // FIXME: Portability. This should be a sys::Path interface, this doesn't + // handle things like C:\foo.txt right, nor win32 \\network\device\blah. + if (FilenameStart[0] == '/') { + CurDir = 0; + + // If this was an #include_next "/absolute/file", fail. + if (FromDir) return 0; + + // Otherwise, just return the file. + return FileMgr.getFile(FilenameStart, FilenameEnd); + } + + // Step #0, unless disabled, check to see if the file is in the #includer's + // directory. This has to be based on CurFileEnt, not CurDir, because + // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and + // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h". + // This search is not done for <> headers. + if (CurFileEnt && !isAngled && !NoCurDirSearch) { + llvm::SmallString<1024> TmpDir; + // Concatenate the requested file onto the directory. + // FIXME: Portability. Filename concatenation should be in sys::Path. + TmpDir += CurFileEnt->getDir()->getName(); + TmpDir.push_back('/'); + TmpDir.append(FilenameStart, FilenameEnd); + if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) { + // Leave CurDir unset. + // This file is a system header or C++ unfriendly if the old file is. + // + // Note that the temporary 'DirInfo' is required here, as either call to + // getFileInfo could resize the vector and we don't want to rely on order + // of evaluation. + unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo; + getFileInfo(FE).DirInfo = DirInfo; + return FE; + } + } + + CurDir = 0; + + // If this is a system #include, ignore the user #include locs. + unsigned i = isAngled ? SystemDirIdx : 0; + + // If this is a #include_next request, start searching after the directory the + // file was found in. + if (FromDir) + i = FromDir-&SearchDirs[0]; + + // Cache all of the lookups performed by this method. Many headers are + // multiply included, and the "pragma once" optimization prevents them from + // being relex/pp'd, but they would still have to search through a + // (potentially huge) series of SearchDirs to find it. + std::pair &CacheLookup = + LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue(); + + // If the entry has been previously looked up, the first value will be + // non-zero. If the value is equal to i (the start point of our search), then + // this is a matching hit. + if (CacheLookup.first == i+1) { + // Skip querying potentially lots of directories for this lookup. + i = CacheLookup.second; + } else { + // Otherwise, this is the first query, or the previous query didn't match + // our search start. We will fill in our found location below, so prime the + // start point value. + CacheLookup.first = i+1; + } + + // Check each directory in sequence to see if it contains this file. + for (; i != SearchDirs.size(); ++i) { + const FileEntry *FE = + SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this); + if (!FE) continue; + + CurDir = &SearchDirs[i]; + + // This file is a system header or C++ unfriendly if the dir is. + getFileInfo(FE).DirInfo = CurDir->getDirCharacteristic(); + + // Remember this location for the next lookup we do. + CacheLookup.second = i; + return FE; + } + + // Otherwise, didn't find it. Remember we didn't find this. + CacheLookup.second = SearchDirs.size(); + return 0; +} + +/// LookupSubframeworkHeader - Look up a subframework for the specified +/// #include file. For example, if #include'ing from +/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox +/// is a subframework within Carbon.framework. If so, return the FileEntry +/// for the designated file, otherwise return null. +const FileEntry *HeaderSearch:: +LookupSubframeworkHeader(const char *FilenameStart, + const char *FilenameEnd, + const FileEntry *ContextFileEnt) { + assert(ContextFileEnt && "No context file?"); + + // Framework names must have a '/' in the filename. Find it. + const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/'); + if (SlashPos == FilenameEnd) return 0; + + // Look up the base framework name of the ContextFileEnt. + const char *ContextName = ContextFileEnt->getName(); + + // If the context info wasn't a framework, couldn't be a subframework. + const char *FrameworkPos = strstr(ContextName, ".framework/"); + if (FrameworkPos == 0) + return 0; + + llvm::SmallString<1024> FrameworkName(ContextName, + FrameworkPos+strlen(".framework/")); + + // Append Frameworks/HIToolbox.framework/ + FrameworkName += "Frameworks/"; + FrameworkName.append(FilenameStart, SlashPos); + FrameworkName += ".framework/"; + + llvm::StringMapEntry &CacheLookup = + FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos); + + // Some other location? + if (CacheLookup.getValue() && + CacheLookup.getKeyLength() == FrameworkName.size() && + memcmp(CacheLookup.getKeyData(), &FrameworkName[0], + CacheLookup.getKeyLength()) != 0) + return 0; + + // Cache subframework. + if (CacheLookup.getValue() == 0) { + ++NumSubFrameworkLookups; + + // If the framework dir doesn't exist, we fail. + const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(), + FrameworkName.end()); + if (Dir == 0) return 0; + + // Otherwise, if it does, remember that this is the right direntry for this + // framework. + CacheLookup.setValue(Dir); + } + + const FileEntry *FE = 0; + + // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h" + llvm::SmallString<1024> HeadersFilename(FrameworkName); + HeadersFilename += "Headers/"; + HeadersFilename.append(SlashPos+1, FilenameEnd); + if (!(FE = FileMgr.getFile(HeadersFilename.begin(), + HeadersFilename.end()))) { + + // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h" + HeadersFilename = FrameworkName; + HeadersFilename += "PrivateHeaders/"; + HeadersFilename.append(SlashPos+1, FilenameEnd); + if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end()))) + return 0; + } + + // This file is a system header or C++ unfriendly if the old file is. + // + // Note that the temporary 'DirInfo' is required here, as either call to + // getFileInfo could resize the vector and we don't want to rely on order + // of evaluation. + unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo; + getFileInfo(FE).DirInfo = DirInfo; + return FE; +} + +//===----------------------------------------------------------------------===// +// File Info Management. +//===----------------------------------------------------------------------===// + + +/// getFileInfo - Return the PerFileInfo structure for the specified +/// FileEntry. +HeaderSearch::PerFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { + if (FE->getUID() >= FileInfo.size()) + FileInfo.resize(FE->getUID()+1); + return FileInfo[FE->getUID()]; +} + +/// ShouldEnterIncludeFile - Mark the specified file as a target of of a +/// #include, #include_next, or #import directive. Return false if #including +/// the file will have no effect or true if we should include it. +bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ + ++NumIncluded; // Count # of attempted #includes. + + // Get information about this file. + PerFileInfo &FileInfo = getFileInfo(File); + + // If this is a #import directive, check that we have not already imported + // this header. + if (isImport) { + // If this has already been imported, don't import it again. + FileInfo.isImport = true; + + // Has this already been #import'ed or #include'd? + if (FileInfo.NumIncludes) return false; + } else { + // Otherwise, if this is a #include of a file that was previously #import'd + // or if this is the second #include of a #pragma once file, ignore it. + if (FileInfo.isImport) + return false; + } + + // Next, check to see if the file is wrapped with #ifndef guards. If so, and + // if the macro that guards it is defined, we know the #include has no effect. + if (FileInfo.ControllingMacro && + FileInfo.ControllingMacro->hasMacroDefinition()) { + ++NumMultiIncludeFileOptzn; + return false; + } + + // Increment the number of times this file has been included. + ++FileInfo.NumIncludes; + + return true; +} + + diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp new file mode 100644 index 00000000000..98bbb386305 --- /dev/null +++ b/clang/lib/Lex/Lexer.cpp @@ -0,0 +1,1661 @@ +//===--- Lexer.cpp - C Language Family Lexer ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Lexer and Token interfaces. +// +//===----------------------------------------------------------------------===// +// +// TODO: GCC Diagnostics emitted by the lexer: +// PEDWARN: (form feed|vertical tab) in preprocessing directive +// +// Universal characters, unicode, char mapping: +// WARNING: `%.*s' is not in NFKC +// WARNING: `%.*s' is not in NFC +// +// Other: +// TODO: Options to support: +// -fexec-charset,-fwide-exec-charset +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include +using namespace clang; + +static void InitCharacterInfo(); + +//===----------------------------------------------------------------------===// +// Token Class Implementation +//===----------------------------------------------------------------------===// + +/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. +bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const { + return is(tok::identifier) && + getIdentifierInfo()->getObjCKeywordID() == objcKey; +} + +/// getObjCKeywordID - Return the ObjC keyword kind. +tok::ObjCKeywordKind Token::getObjCKeywordID() const { + IdentifierInfo *specId = getIdentifierInfo(); + return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; +} + +/// isNamedIdentifier - Return true if this token is a ppidentifier with the +/// specified name. For example, tok.isNamedIdentifier("this"). +bool Token::isNamedIdentifier(const char *Name) const { + return IdentInfo && !strcmp(IdentInfo->getName(), Name); +} + + +//===----------------------------------------------------------------------===// +// Lexer Class Implementation +//===----------------------------------------------------------------------===// + + +/// Lexer constructor - Create a new lexer object for the specified buffer +/// with the specified preprocessor managing the lexing process. This lexer +/// assumes that the associated file buffer and Preprocessor objects will +/// outlive it, so it doesn't take ownership of either of them. +Lexer::Lexer(SourceLocation fileloc, Preprocessor &pp, + const char *BufStart, const char *BufEnd) + : FileLoc(fileloc), PP(&pp), Features(pp.getLangOptions()) { + + SourceManager &SourceMgr = PP->getSourceManager(); + unsigned InputFileID = SourceMgr.getPhysicalLoc(FileLoc).getFileID(); + const llvm::MemoryBuffer *InputFile = SourceMgr.getBuffer(InputFileID); + + Is_PragmaLexer = false; + InitCharacterInfo(); + + // BufferStart must always be InputFile->getBufferStart(). + BufferStart = InputFile->getBufferStart(); + + // BufferPtr and BufferEnd can start out somewhere inside the current buffer. + // If unspecified, they starts at the start/end of the buffer. + BufferPtr = BufStart ? BufStart : BufferStart; + BufferEnd = BufEnd ? BufEnd : InputFile->getBufferEnd(); + + assert(BufferEnd[0] == 0 && + "We assume that the input buffer has a null character at the end" + " to simplify lexing!"); + + // Start of the file is a start of line. + IsAtStartOfLine = true; + + // We are not after parsing a #. + ParsingPreprocessorDirective = false; + + // We are not after parsing #include. + ParsingFilename = false; + + // We are not in raw mode. Raw mode disables diagnostics and interpretation + // of tokens (e.g. identifiers, thus disabling macro expansion). It is used + // to quickly lex the tokens of the buffer, e.g. when handling a "#if 0" block + // or otherwise skipping over tokens. + LexingRawMode = false; + + // Default to keeping comments if requested. + KeepCommentMode = PP->getCommentRetentionState(); +} + +/// Lexer constructor - Create a new raw lexer object. This object is only +/// suitable for calls to 'LexRawToken'. This lexer assumes that the +/// associated file buffer will outlive it, so it doesn't take ownership of +/// either of them. +Lexer::Lexer(SourceLocation fileloc, const LangOptions &features, + const char *BufStart, const char *BufEnd) + : FileLoc(fileloc), PP(0), Features(features) { + Is_PragmaLexer = false; + InitCharacterInfo(); + + BufferStart = BufStart; + BufferPtr = BufStart; + BufferEnd = BufEnd; + + assert(BufferEnd[0] == 0 && + "We assume that the input buffer has a null character at the end" + " to simplify lexing!"); + + // Start of the file is a start of line. + IsAtStartOfLine = true; + + // We are not after parsing a #. + ParsingPreprocessorDirective = false; + + // We are not after parsing #include. + ParsingFilename = false; + + // We *are* in raw mode. + LexingRawMode = true; + + // Never keep comments in raw mode. + KeepCommentMode = false; +} + + +/// Stringify - Convert the specified string into a C string, with surrounding +/// ""'s, and with escaped \ and " characters. +std::string Lexer::Stringify(const std::string &Str, bool Charify) { + std::string Result = Str; + char Quote = Charify ? '\'' : '"'; + for (unsigned i = 0, e = Result.size(); i != e; ++i) { + if (Result[i] == '\\' || Result[i] == Quote) { + Result.insert(Result.begin()+i, '\\'); + ++i; ++e; + } + } + return Result; +} + +/// Stringify - Convert the specified string into a C string by escaping '\' +/// and " characters. This does not add surrounding ""'s to the string. +void Lexer::Stringify(llvm::SmallVectorImpl &Str) { + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + if (Str[i] == '\\' || Str[i] == '"') { + Str.insert(Str.begin()+i, '\\'); + ++i; ++e; + } + } +} + + +/// MeasureTokenLength - Relex the token at the specified location and return +/// its length in bytes in the input file. If the token needs cleaning (e.g. +/// includes a trigraph or an escaped newline) then this count includes bytes +/// that are part of that. +unsigned Lexer::MeasureTokenLength(SourceLocation Loc, + const SourceManager &SM) { + // If this comes from a macro expansion, we really do want the macro name, not + // the token this macro expanded to. + Loc = SM.getLogicalLoc(Loc); + + const char *StrData = SM.getCharacterData(Loc); + + // TODO: this could be special cased for common tokens like identifiers, ')', + // etc to make this faster, if it mattered. Just look at StrData[0] to handle + // all obviously single-char tokens. This could use + // Lexer::isObviouslySimpleCharacter for example to handle identifiers or + // something. + + + const char *BufEnd = SM.getBufferData(Loc.getFileID()).second; + + // Create a langops struct and enable trigraphs. This is sufficient for + // measuring tokens. + LangOptions LangOpts; + LangOpts.Trigraphs = true; + + // Create a lexer starting at the beginning of this token. + Lexer TheLexer(Loc, LangOpts, StrData, BufEnd); + Token TheTok; + TheLexer.LexRawToken(TheTok); + return TheTok.getLength(); +} + +//===----------------------------------------------------------------------===// +// Character information. +//===----------------------------------------------------------------------===// + +static unsigned char CharInfo[256]; + +enum { + CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0' + CHAR_VERT_WS = 0x02, // '\r', '\n' + CHAR_LETTER = 0x04, // a-z,A-Z + CHAR_NUMBER = 0x08, // 0-9 + CHAR_UNDER = 0x10, // _ + CHAR_PERIOD = 0x20 // . +}; + +static void InitCharacterInfo() { + static bool isInited = false; + if (isInited) return; + isInited = true; + + // Intiialize the CharInfo table. + // TODO: statically initialize this. + CharInfo[(int)' '] = CharInfo[(int)'\t'] = + CharInfo[(int)'\f'] = CharInfo[(int)'\v'] = CHAR_HORZ_WS; + CharInfo[(int)'\n'] = CharInfo[(int)'\r'] = CHAR_VERT_WS; + + CharInfo[(int)'_'] = CHAR_UNDER; + CharInfo[(int)'.'] = CHAR_PERIOD; + for (unsigned i = 'a'; i <= 'z'; ++i) + CharInfo[i] = CharInfo[i+'A'-'a'] = CHAR_LETTER; + for (unsigned i = '0'; i <= '9'; ++i) + CharInfo[i] = CHAR_NUMBER; +} + +/// isIdentifierBody - Return true if this is the body character of an +/// identifier, which is [a-zA-Z0-9_]. +static inline bool isIdentifierBody(unsigned char c) { + return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER)) ? true : false; +} + +/// isHorizontalWhitespace - Return true if this character is horizontal +/// whitespace: ' ', '\t', '\f', '\v'. Note that this returns false for '\0'. +static inline bool isHorizontalWhitespace(unsigned char c) { + return (CharInfo[c] & CHAR_HORZ_WS) ? true : false; +} + +/// isWhitespace - Return true if this character is horizontal or vertical +/// whitespace: ' ', '\t', '\f', '\v', '\n', '\r'. Note that this returns false +/// for '\0'. +static inline bool isWhitespace(unsigned char c) { + return (CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS)) ? true : false; +} + +/// isNumberBody - Return true if this is the body character of an +/// preprocessing number, which is [a-zA-Z0-9_.]. +static inline bool isNumberBody(unsigned char c) { + return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ? + true : false; +} + + +//===----------------------------------------------------------------------===// +// Diagnostics forwarding code. +//===----------------------------------------------------------------------===// + +/// GetMappedTokenLoc - If lexing out of a 'mapped buffer', where we pretend the +/// lexer buffer was all instantiated at a single point, perform the mapping. +/// This is currently only used for _Pragma implementation, so it is the slow +/// path of the hot getSourceLocation method. Do not allow it to be inlined. +static SourceLocation GetMappedTokenLoc(Preprocessor &PP, + SourceLocation FileLoc, + unsigned CharNo) DISABLE_INLINE; +static SourceLocation GetMappedTokenLoc(Preprocessor &PP, + SourceLocation FileLoc, + unsigned CharNo) { + // Otherwise, we're lexing "mapped tokens". This is used for things like + // _Pragma handling. Combine the instantiation location of FileLoc with the + // physical location. + SourceManager &SourceMgr = PP.getSourceManager(); + + // Create a new SLoc which is expanded from logical(FileLoc) but whose + // characters come from phys(FileLoc)+Offset. + SourceLocation VirtLoc = SourceMgr.getLogicalLoc(FileLoc); + SourceLocation PhysLoc = SourceMgr.getPhysicalLoc(FileLoc); + PhysLoc = SourceLocation::getFileLoc(PhysLoc.getFileID(), CharNo); + return SourceMgr.getInstantiationLoc(PhysLoc, VirtLoc); +} + +/// getSourceLocation - Return a source location identifier for the specified +/// offset in the current file. +SourceLocation Lexer::getSourceLocation(const char *Loc) const { + assert(Loc >= BufferStart && Loc <= BufferEnd && + "Location out of range for this buffer!"); + + // In the normal case, we're just lexing from a simple file buffer, return + // the file id from FileLoc with the offset specified. + unsigned CharNo = Loc-BufferStart; + if (FileLoc.isFileID()) + return SourceLocation::getFileLoc(FileLoc.getFileID(), CharNo); + + assert(PP && "This doesn't work on raw lexers"); + return GetMappedTokenLoc(*PP, FileLoc, CharNo); +} + +/// Diag - Forwarding function for diagnostics. This translate a source +/// position in the current buffer into a SourceLocation object for rendering. +void Lexer::Diag(const char *Loc, unsigned DiagID, + const std::string &Msg) const { + if (LexingRawMode && Diagnostic::isBuiltinNoteWarningOrExtension(DiagID)) + return; + PP->Diag(getSourceLocation(Loc), DiagID, Msg); +} +void Lexer::Diag(SourceLocation Loc, unsigned DiagID, + const std::string &Msg) const { + if (LexingRawMode && Diagnostic::isBuiltinNoteWarningOrExtension(DiagID)) + return; + PP->Diag(Loc, DiagID, Msg); +} + + +//===----------------------------------------------------------------------===// +// Trigraph and Escaped Newline Handling Code. +//===----------------------------------------------------------------------===// + +/// GetTrigraphCharForLetter - Given a character that occurs after a ?? pair, +/// return the decoded trigraph letter it corresponds to, or '\0' if nothing. +static char GetTrigraphCharForLetter(char Letter) { + switch (Letter) { + default: return 0; + case '=': return '#'; + case ')': return ']'; + case '(': return '['; + case '!': return '|'; + case '\'': return '^'; + case '>': return '}'; + case '/': return '\\'; + case '<': return '{'; + case '-': return '~'; + } +} + +/// DecodeTrigraphChar - If the specified character is a legal trigraph when +/// prefixed with ??, emit a trigraph warning. If trigraphs are enabled, +/// return the result character. Finally, emit a warning about trigraph use +/// whether trigraphs are enabled or not. +static char DecodeTrigraphChar(const char *CP, Lexer *L) { + char Res = GetTrigraphCharForLetter(*CP); + if (Res && L) { + if (!L->getFeatures().Trigraphs) { + L->Diag(CP-2, diag::trigraph_ignored); + return 0; + } else { + L->Diag(CP-2, diag::trigraph_converted, std::string()+Res); + } + } + return Res; +} + +/// getCharAndSizeSlow - Peek a single 'character' from the specified buffer, +/// get its size, and return it. This is tricky in several cases: +/// 1. If currently at the start of a trigraph, we warn about the trigraph, +/// then either return the trigraph (skipping 3 chars) or the '?', +/// depending on whether trigraphs are enabled or not. +/// 2. If this is an escaped newline (potentially with whitespace between +/// the backslash and newline), implicitly skip the newline and return +/// the char after it. +/// 3. If this is a UCN, return it. FIXME: C++ UCN's? +/// +/// This handles the slow/uncommon case of the getCharAndSize method. Here we +/// know that we can accumulate into Size, and that we have already incremented +/// Ptr by Size bytes. +/// +/// NOTE: When this method is updated, getCharAndSizeSlowNoWarn (below) should +/// be updated to match. +/// +char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size, + Token *Tok) { + // If we have a slash, look for an escaped newline. + if (Ptr[0] == '\\') { + ++Size; + ++Ptr; +Slash: + // Common case, backslash-char where the char is not whitespace. + if (!isWhitespace(Ptr[0])) return '\\'; + + // See if we have optional whitespace characters followed by a newline. + { + unsigned SizeTmp = 0; + do { + ++SizeTmp; + if (Ptr[SizeTmp-1] == '\n' || Ptr[SizeTmp-1] == '\r') { + // Remember that this token needs to be cleaned. + if (Tok) Tok->setFlag(Token::NeedsCleaning); + + // Warn if there was whitespace between the backslash and newline. + if (SizeTmp != 1 && Tok) + Diag(Ptr, diag::backslash_newline_space); + + // If this is a \r\n or \n\r, skip the newlines. + if ((Ptr[SizeTmp] == '\r' || Ptr[SizeTmp] == '\n') && + Ptr[SizeTmp-1] != Ptr[SizeTmp]) + ++SizeTmp; + + // Found backslash. Parse the char after it. + Size += SizeTmp; + Ptr += SizeTmp; + // Use slow version to accumulate a correct size field. + return getCharAndSizeSlow(Ptr, Size, Tok); + } + } while (isWhitespace(Ptr[SizeTmp])); + } + + // Otherwise, this is not an escaped newline, just return the slash. + return '\\'; + } + + // If this is a trigraph, process it. + if (Ptr[0] == '?' && Ptr[1] == '?') { + // If this is actually a legal trigraph (not something like "??x"), emit + // a trigraph warning. If so, and if trigraphs are enabled, return it. + if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) { + // Remember that this token needs to be cleaned. + if (Tok) Tok->setFlag(Token::NeedsCleaning); + + Ptr += 3; + Size += 3; + if (C == '\\') goto Slash; + return C; + } + } + + // If this is neither, return a single character. + ++Size; + return *Ptr; +} + + +/// getCharAndSizeSlowNoWarn - Handle the slow/uncommon case of the +/// getCharAndSizeNoWarn method. Here we know that we can accumulate into Size, +/// and that we have already incremented Ptr by Size bytes. +/// +/// NOTE: When this method is updated, getCharAndSizeSlow (above) should +/// be updated to match. +char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &Features) { + // If we have a slash, look for an escaped newline. + if (Ptr[0] == '\\') { + ++Size; + ++Ptr; +Slash: + // Common case, backslash-char where the char is not whitespace. + if (!isWhitespace(Ptr[0])) return '\\'; + + // See if we have optional whitespace characters followed by a newline. + { + unsigned SizeTmp = 0; + do { + ++SizeTmp; + if (Ptr[SizeTmp-1] == '\n' || Ptr[SizeTmp-1] == '\r') { + + // If this is a \r\n or \n\r, skip the newlines. + if ((Ptr[SizeTmp] == '\r' || Ptr[SizeTmp] == '\n') && + Ptr[SizeTmp-1] != Ptr[SizeTmp]) + ++SizeTmp; + + // Found backslash. Parse the char after it. + Size += SizeTmp; + Ptr += SizeTmp; + + // Use slow version to accumulate a correct size field. + return getCharAndSizeSlowNoWarn(Ptr, Size, Features); + } + } while (isWhitespace(Ptr[SizeTmp])); + } + + // Otherwise, this is not an escaped newline, just return the slash. + return '\\'; + } + + // If this is a trigraph, process it. + if (Features.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') { + // If this is actually a legal trigraph (not something like "??x"), return + // it. + if (char C = GetTrigraphCharForLetter(Ptr[2])) { + Ptr += 3; + Size += 3; + if (C == '\\') goto Slash; + return C; + } + } + + // If this is neither, return a single character. + ++Size; + return *Ptr; +} + +//===----------------------------------------------------------------------===// +// Helper methods for lexing. +//===----------------------------------------------------------------------===// + +void Lexer::LexIdentifier(Token &Result, const char *CurPtr) { + // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] + unsigned Size; + unsigned char C = *CurPtr++; + while (isIdentifierBody(C)) { + C = *CurPtr++; + } + --CurPtr; // Back up over the skipped character. + + // Fast path, no $,\,? in identifier found. '\' might be an escaped newline + // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN. + // FIXME: UCNs. + if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) { +FinishIdentifier: + const char *IdStart = BufferPtr; + FormTokenWithChars(Result, CurPtr); + Result.setKind(tok::identifier); + + // If we are in raw mode, return this identifier raw. There is no need to + // look up identifier information or attempt to macro expand it. + if (LexingRawMode) return; + + // Fill in Result.IdentifierInfo, looking up the identifier in the + // identifier table. + PP->LookUpIdentifierInfo(Result, IdStart); + + // Finally, now that we know we have an identifier, pass this off to the + // preprocessor, which may macro expand it or something. + return PP->HandleIdentifier(Result); + } + + // Otherwise, $,\,? in identifier found. Enter slower path. + + C = getCharAndSize(CurPtr, Size); + while (1) { + if (C == '$') { + // If we hit a $ and they are not supported in identifiers, we are done. + if (!Features.DollarIdents) goto FinishIdentifier; + + // Otherwise, emit a diagnostic and continue. + Diag(CurPtr, diag::ext_dollar_in_identifier); + CurPtr = ConsumeChar(CurPtr, Size, Result); + C = getCharAndSize(CurPtr, Size); + continue; + } else if (!isIdentifierBody(C)) { // FIXME: UCNs. + // Found end of identifier. + goto FinishIdentifier; + } + + // Otherwise, this character is good, consume it. + CurPtr = ConsumeChar(CurPtr, Size, Result); + + C = getCharAndSize(CurPtr, Size); + while (isIdentifierBody(C)) { // FIXME: UCNs. + CurPtr = ConsumeChar(CurPtr, Size, Result); + C = getCharAndSize(CurPtr, Size); + } + } +} + + +/// LexNumericConstant - Lex the remainer of a integer or floating point +/// constant. From[-1] is the first character lexed. Return the end of the +/// constant. +void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { + unsigned Size; + char C = getCharAndSize(CurPtr, Size); + char PrevCh = 0; + while (isNumberBody(C)) { // FIXME: UCNs? + CurPtr = ConsumeChar(CurPtr, Size, Result); + PrevCh = C; + C = getCharAndSize(CurPtr, Size); + } + + // If we fell out, check for a sign, due to 1e+12. If we have one, continue. + if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) + return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); + + // If we have a hex FP constant, continue. + if (Features.HexFloats && + (C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) + return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); + + Result.setKind(tok::numeric_constant); + + // Update the location of token as well as BufferPtr. + FormTokenWithChars(Result, CurPtr); +} + +/// LexStringLiteral - Lex the remainder of a string literal, after having lexed +/// either " or L". +void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide){ + const char *NulCharacter = 0; // Does this string contain the \0 character? + + char C = getAndAdvanceChar(CurPtr, Result); + while (C != '"') { + // Skip escaped characters. + if (C == '\\') { + // Skip the escaped character. + C = getAndAdvanceChar(CurPtr, Result); + } else if (C == '\n' || C == '\r' || // Newline. + (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. + if (!LexingRawMode) Diag(BufferPtr, diag::err_unterminated_string); + Result.setKind(tok::unknown); + FormTokenWithChars(Result, CurPtr-1); + return; + } else if (C == 0) { + NulCharacter = CurPtr-1; + } + C = getAndAdvanceChar(CurPtr, Result); + } + + // If a nul character existed in the string, warn about it. + if (NulCharacter) Diag(NulCharacter, diag::null_in_string); + + Result.setKind(Wide ? tok::wide_string_literal : tok::string_literal); + + // Update the location of the token as well as the BufferPtr instance var. + FormTokenWithChars(Result, CurPtr); +} + +/// LexAngledStringLiteral - Lex the remainder of an angled string literal, +/// after having lexed the '<' character. This is used for #include filenames. +void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) { + const char *NulCharacter = 0; // Does this string contain the \0 character? + + char C = getAndAdvanceChar(CurPtr, Result); + while (C != '>') { + // Skip escaped characters. + if (C == '\\') { + // Skip the escaped character. + C = getAndAdvanceChar(CurPtr, Result); + } else if (C == '\n' || C == '\r' || // Newline. + (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. + if (!LexingRawMode) Diag(BufferPtr, diag::err_unterminated_string); + Result.setKind(tok::unknown); + FormTokenWithChars(Result, CurPtr-1); + return; + } else if (C == 0) { + NulCharacter = CurPtr-1; + } + C = getAndAdvanceChar(CurPtr, Result); + } + + // If a nul character existed in the string, warn about it. + if (NulCharacter) Diag(NulCharacter, diag::null_in_string); + + Result.setKind(tok::angle_string_literal); + + // Update the location of token as well as BufferPtr. + FormTokenWithChars(Result, CurPtr); +} + + +/// LexCharConstant - Lex the remainder of a character constant, after having +/// lexed either ' or L'. +void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { + const char *NulCharacter = 0; // Does this character contain the \0 character? + + // Handle the common case of 'x' and '\y' efficiently. + char C = getAndAdvanceChar(CurPtr, Result); + if (C == '\'') { + if (!LexingRawMode) Diag(BufferPtr, diag::err_empty_character); + Result.setKind(tok::unknown); + FormTokenWithChars(Result, CurPtr); + return; + } else if (C == '\\') { + // Skip the escaped character. + // FIXME: UCN's. + C = getAndAdvanceChar(CurPtr, Result); + } + + if (C && C != '\n' && C != '\r' && CurPtr[0] == '\'') { + ++CurPtr; + } else { + // Fall back on generic code for embedded nulls, newlines, wide chars. + do { + // Skip escaped characters. + if (C == '\\') { + // Skip the escaped character. + C = getAndAdvanceChar(CurPtr, Result); + } else if (C == '\n' || C == '\r' || // Newline. + (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. + if (!LexingRawMode) Diag(BufferPtr, diag::err_unterminated_char); + Result.setKind(tok::unknown); + FormTokenWithChars(Result, CurPtr-1); + return; + } else if (C == 0) { + NulCharacter = CurPtr-1; + } + C = getAndAdvanceChar(CurPtr, Result); + } while (C != '\''); + } + + if (NulCharacter) Diag(NulCharacter, diag::null_in_char); + + Result.setKind(tok::char_constant); + + // Update the location of token as well as BufferPtr. + FormTokenWithChars(Result, CurPtr); +} + +/// SkipWhitespace - Efficiently skip over a series of whitespace characters. +/// Update BufferPtr to point to the next non-whitespace character and return. +void Lexer::SkipWhitespace(Token &Result, const char *CurPtr) { + // Whitespace - Skip it, then return the token after the whitespace. + unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently. + while (1) { + // Skip horizontal whitespace very aggressively. + while (isHorizontalWhitespace(Char)) + Char = *++CurPtr; + + // Otherwise if we something other than whitespace, we're done. + if (Char != '\n' && Char != '\r') + break; + + if (ParsingPreprocessorDirective) { + // End of preprocessor directive line, let LexTokenInternal handle this. + BufferPtr = CurPtr; + return; + } + + // ok, but handle newline. + // The returned token is at the start of the line. + Result.setFlag(Token::StartOfLine); + // No leading whitespace seen so far. + Result.clearFlag(Token::LeadingSpace); + Char = *++CurPtr; + } + + // If this isn't immediately after a newline, there is leading space. + char PrevChar = CurPtr[-1]; + if (PrevChar != '\n' && PrevChar != '\r') + Result.setFlag(Token::LeadingSpace); + + BufferPtr = CurPtr; +} + +// SkipBCPLComment - We have just read the // characters from input. Skip until +// we find the newline character thats terminate the comment. Then update +/// BufferPtr and return. +bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { + // If BCPL comments aren't explicitly enabled for this language, emit an + // extension warning. + if (!Features.BCPLComment) { + Diag(BufferPtr, diag::ext_bcpl_comment); + + // Mark them enabled so we only emit one warning for this translation + // unit. + Features.BCPLComment = true; + } + + // Scan over the body of the comment. The common case, when scanning, is that + // the comment contains normal ascii characters with nothing interesting in + // them. As such, optimize for this case with the inner loop. + char C; + do { + C = *CurPtr; + // FIXME: Speedup BCPL comment lexing. Just scan for a \n or \r character. + // If we find a \n character, scan backwards, checking to see if it's an + // escaped newline, like we do for block comments. + + // Skip over characters in the fast loop. + while (C != 0 && // Potentially EOF. + C != '\\' && // Potentially escaped newline. + C != '?' && // Potentially trigraph. + C != '\n' && C != '\r') // Newline or DOS-style newline. + C = *++CurPtr; + + // If this is a newline, we're done. + if (C == '\n' || C == '\r') + break; // Found the newline? Break out! + + // Otherwise, this is a hard case. Fall back on getAndAdvanceChar to + // properly decode the character. + const char *OldPtr = CurPtr; + C = getAndAdvanceChar(CurPtr, Result); + + // If we read multiple characters, and one of those characters was a \r or + // \n, then we had an escaped newline within the comment. Emit diagnostic + // unless the next line is also a // comment. + if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') { + for (; OldPtr != CurPtr; ++OldPtr) + if (OldPtr[0] == '\n' || OldPtr[0] == '\r') { + // Okay, we found a // comment that ends in a newline, if the next + // line is also a // comment, but has spaces, don't emit a diagnostic. + if (isspace(C)) { + const char *ForwardPtr = CurPtr; + while (isspace(*ForwardPtr)) // Skip whitespace. + ++ForwardPtr; + if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/') + break; + } + + Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment); + break; + } + } + + if (CurPtr == BufferEnd+1) { --CurPtr; break; } + } while (C != '\n' && C != '\r'); + + // Found but did not consume the newline. + + // If we are returning comments as tokens, return this comment as a token. + if (KeepCommentMode) + return SaveBCPLComment(Result, CurPtr); + + // If we are inside a preprocessor directive and we see the end of line, + // return immediately, so that the lexer can return this as an EOM token. + if (ParsingPreprocessorDirective || CurPtr == BufferEnd) { + BufferPtr = CurPtr; + return true; + } + + // Otherwise, eat the \n character. We don't care if this is a \n\r or + // \r\n sequence. + ++CurPtr; + + // The next returned token is at the start of the line. + Result.setFlag(Token::StartOfLine); + // No leading whitespace seen so far. + Result.clearFlag(Token::LeadingSpace); + BufferPtr = CurPtr; + return true; +} + +/// SaveBCPLComment - If in save-comment mode, package up this BCPL comment in +/// an appropriate way and return it. +bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) { + Result.setKind(tok::comment); + FormTokenWithChars(Result, CurPtr); + + // If this BCPL-style comment is in a macro definition, transmogrify it into + // a C-style block comment. + if (ParsingPreprocessorDirective) { + std::string Spelling = PP->getSpelling(Result); + assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?"); + Spelling[1] = '*'; // Change prefix to "/*". + Spelling += "*/"; // add suffix. + + Result.setLocation(PP->CreateString(&Spelling[0], Spelling.size(), + Result.getLocation())); + Result.setLength(Spelling.size()); + } + return false; +} + +/// isBlockCommentEndOfEscapedNewLine - Return true if the specified newline +/// character (either \n or \r) is part of an escaped newline sequence. Issue a +/// diagnostic if so. We know that the is inside of a block comment. +static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, + Lexer *L) { + assert(CurPtr[0] == '\n' || CurPtr[0] == '\r'); + + // Back up off the newline. + --CurPtr; + + // If this is a two-character newline sequence, skip the other character. + if (CurPtr[0] == '\n' || CurPtr[0] == '\r') { + // \n\n or \r\r -> not escaped newline. + if (CurPtr[0] == CurPtr[1]) + return false; + // \n\r or \r\n -> skip the newline. + --CurPtr; + } + + // If we have horizontal whitespace, skip over it. We allow whitespace + // between the slash and newline. + bool HasSpace = false; + while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) { + --CurPtr; + HasSpace = true; + } + + // If we have a slash, we know this is an escaped newline. + if (*CurPtr == '\\') { + if (CurPtr[-1] != '*') return false; + } else { + // It isn't a slash, is it the ?? / trigraph? + if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' || + CurPtr[-3] != '*') + return false; + + // This is the trigraph ending the comment. Emit a stern warning! + CurPtr -= 2; + + // If no trigraphs are enabled, warn that we ignored this trigraph and + // ignore this * character. + if (!L->getFeatures().Trigraphs) { + L->Diag(CurPtr, diag::trigraph_ignored_block_comment); + return false; + } + L->Diag(CurPtr, diag::trigraph_ends_block_comment); + } + + // Warn about having an escaped newline between the */ characters. + L->Diag(CurPtr, diag::escaped_newline_block_comment_end); + + // If there was space between the backslash and newline, warn about it. + if (HasSpace) L->Diag(CurPtr, diag::backslash_newline_space); + + return true; +} + +#ifdef __SSE2__ +#include +#elif __ALTIVEC__ +#include +#undef bool +#endif + +/// SkipBlockComment - We have just read the /* characters from input. Read +/// until we find the */ characters that terminate the comment. Note that we +/// don't bother decoding trigraphs or escaped newlines in block comments, +/// because they cannot cause the comment to end. The only thing that can +/// happen is the comment could end with an escaped newline between the */ end +/// of comment. +bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { + // Scan one character past where we should, looking for a '/' character. Once + // we find it, check to see if it was preceeded by a *. This common + // optimization helps people who like to put a lot of * characters in their + // comments. + + // The first character we get with newlines and trigraphs skipped to handle + // the degenerate /*/ case below correctly if the * has an escaped newline + // after it. + unsigned CharSize; + unsigned char C = getCharAndSize(CurPtr, CharSize); + CurPtr += CharSize; + if (C == 0 && CurPtr == BufferEnd+1) { + Diag(BufferPtr, diag::err_unterminated_block_comment); + BufferPtr = CurPtr-1; + return true; + } + + // Check to see if the first character after the '/*' is another /. If so, + // then this slash does not end the block comment, it is part of it. + if (C == '/') + C = *CurPtr++; + + while (1) { + // Skip over all non-interesting characters until we find end of buffer or a + // (probably ending) '/' character. + if (CurPtr + 24 < BufferEnd) { + // While not aligned to a 16-byte boundary. + while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0) + C = *CurPtr++; + + if (C == '/') goto FoundSlash; + +#ifdef __SSE2__ + __m128i Slashes = _mm_set_epi8('/', '/', '/', '/', '/', '/', '/', '/', + '/', '/', '/', '/', '/', '/', '/', '/'); + while (CurPtr+16 <= BufferEnd && + _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes)) == 0) + CurPtr += 16; +#elif __ALTIVEC__ + __vector unsigned char Slashes = { + '/', '/', '/', '/', '/', '/', '/', '/', + '/', '/', '/', '/', '/', '/', '/', '/' + }; + while (CurPtr+16 <= BufferEnd && + !vec_any_eq(*(vector unsigned char*)CurPtr, Slashes)) + CurPtr += 16; +#else + // Scan for '/' quickly. Many block comments are very large. + while (CurPtr[0] != '/' && + CurPtr[1] != '/' && + CurPtr[2] != '/' && + CurPtr[3] != '/' && + CurPtr+4 < BufferEnd) { + CurPtr += 4; + } +#endif + + // It has to be one of the bytes scanned, increment to it and read one. + C = *CurPtr++; + } + + // Loop to scan the remainder. + while (C != '/' && C != '\0') + C = *CurPtr++; + + FoundSlash: + if (C == '/') { + if (CurPtr[-2] == '*') // We found the final */. We're done! + break; + + if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) { + if (isEndOfBlockCommentWithEscapedNewLine(CurPtr-2, this)) { + // We found the final */, though it had an escaped newline between the + // * and /. We're done! + break; + } + } + if (CurPtr[0] == '*' && CurPtr[1] != '/') { + // If this is a /* inside of the comment, emit a warning. Don't do this + // if this is a /*/, which will end the comment. This misses cases with + // embedded escaped newlines, but oh well. + Diag(CurPtr-1, diag::nested_block_comment); + } + } else if (C == 0 && CurPtr == BufferEnd+1) { + Diag(BufferPtr, diag::err_unterminated_block_comment); + // Note: the user probably forgot a */. We could continue immediately + // after the /*, but this would involve lexing a lot of what really is the + // comment, which surely would confuse the parser. + BufferPtr = CurPtr-1; + return true; + } + C = *CurPtr++; + } + + // If we are returning comments as tokens, return this comment as a token. + if (KeepCommentMode) { + Result.setKind(tok::comment); + FormTokenWithChars(Result, CurPtr); + return false; + } + + // It is common for the tokens immediately after a /**/ comment to be + // whitespace. Instead of going through the big switch, handle it + // efficiently now. + if (isHorizontalWhitespace(*CurPtr)) { + Result.setFlag(Token::LeadingSpace); + SkipWhitespace(Result, CurPtr+1); + return true; + } + + // Otherwise, just return so that the next character will be lexed as a token. + BufferPtr = CurPtr; + Result.setFlag(Token::LeadingSpace); + return true; +} + +//===----------------------------------------------------------------------===// +// Primary Lexing Entry Points +//===----------------------------------------------------------------------===// + +/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and +/// (potentially) macro expand the filename. +void Lexer::LexIncludeFilename(Token &FilenameTok) { + assert(ParsingPreprocessorDirective && + ParsingFilename == false && + "Must be in a preprocessing directive!"); + + // We are now parsing a filename! + ParsingFilename = true; + + // Lex the filename. + Lex(FilenameTok); + + // We should have obtained the filename now. + ParsingFilename = false; + + // No filename? + if (FilenameTok.is(tok::eom)) + Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); +} + +/// ReadToEndOfLine - Read the rest of the current preprocessor line as an +/// uninterpreted string. This switches the lexer out of directive mode. +std::string Lexer::ReadToEndOfLine() { + assert(ParsingPreprocessorDirective && ParsingFilename == false && + "Must be in a preprocessing directive!"); + std::string Result; + Token Tmp; + + // CurPtr - Cache BufferPtr in an automatic variable. + const char *CurPtr = BufferPtr; + while (1) { + char Char = getAndAdvanceChar(CurPtr, Tmp); + switch (Char) { + default: + Result += Char; + break; + case 0: // Null. + // Found end of file? + if (CurPtr-1 != BufferEnd) { + // Nope, normal character, continue. + Result += Char; + break; + } + // FALL THROUGH. + case '\r': + case '\n': + // Okay, we found the end of the line. First, back up past the \0, \r, \n. + assert(CurPtr[-1] == Char && "Trigraphs for newline?"); + BufferPtr = CurPtr-1; + + // Next, lex the character, which should handle the EOM transition. + Lex(Tmp); + assert(Tmp.is(tok::eom) && "Unexpected token!"); + + // Finally, we're done, return the string we found. + return Result; + } + } +} + +/// LexEndOfFile - CurPtr points to the end of this file. Handle this +/// condition, reporting diagnostics and handling other edge cases as required. +/// This returns true if Result contains a token, false if PP.Lex should be +/// called again. +bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { + // If we hit the end of the file while parsing a preprocessor directive, + // end the preprocessor directive first. The next token returned will + // then be the end of file. + if (ParsingPreprocessorDirective) { + // Done parsing the "line". + ParsingPreprocessorDirective = false; + Result.setKind(tok::eom); + // Update the location of token as well as BufferPtr. + FormTokenWithChars(Result, CurPtr); + + // Restore comment saving mode, in case it was disabled for directive. + KeepCommentMode = PP->getCommentRetentionState(); + return true; // Have a token. + } + + // If we are in raw mode, return this event as an EOF token. Let the caller + // that put us in raw mode handle the event. + if (LexingRawMode) { + Result.startToken(); + BufferPtr = BufferEnd; + FormTokenWithChars(Result, BufferEnd); + Result.setKind(tok::eof); + return true; + } + + // Otherwise, issue diagnostics for unterminated #if and missing newline. + + // If we are in a #if directive, emit an error. + while (!ConditionalStack.empty()) { + Diag(ConditionalStack.back().IfLoc, diag::err_pp_unterminated_conditional); + ConditionalStack.pop_back(); + } + + // If the file was empty or didn't end in a newline, issue a pedwarn. + if (CurPtr[-1] != '\n' && CurPtr[-1] != '\r') + Diag(BufferEnd, diag::ext_no_newline_eof); + + BufferPtr = CurPtr; + + // Finally, let the preprocessor handle this. + return PP->HandleEndOfFile(Result); +} + +/// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from +/// the specified lexer will return a tok::l_paren token, 0 if it is something +/// else and 2 if there are no more tokens in the buffer controlled by the +/// lexer. +unsigned Lexer::isNextPPTokenLParen() { + assert(!LexingRawMode && "How can we expand a macro from a skipping buffer?"); + + // Switch to 'skipping' mode. This will ensure that we can lex a token + // without emitting diagnostics, disables macro expansion, and will cause EOF + // to return an EOF token instead of popping the include stack. + LexingRawMode = true; + + // Save state that can be changed while lexing so that we can restore it. + const char *TmpBufferPtr = BufferPtr; + + Token Tok; + Tok.startToken(); + LexTokenInternal(Tok); + + // Restore state that may have changed. + BufferPtr = TmpBufferPtr; + + // Restore the lexer back to non-skipping mode. + LexingRawMode = false; + + if (Tok.is(tok::eof)) + return 2; + return Tok.is(tok::l_paren); +} + + +/// LexTokenInternal - This implements a simple C family lexer. It is an +/// extremely performance critical piece of code. This assumes that the buffer +/// has a null character at the end of the file. Return true if an error +/// occurred and compilation should terminate, false if normal. This returns a +/// preprocessing token, not a normal token, as such, it is an internal +/// interface. It assumes that the Flags of result have been cleared before +/// calling this. +void Lexer::LexTokenInternal(Token &Result) { +LexNextToken: + // New token, can't need cleaning yet. + Result.clearFlag(Token::NeedsCleaning); + Result.setIdentifierInfo(0); + + // CurPtr - Cache BufferPtr in an automatic variable. + const char *CurPtr = BufferPtr; + + // Small amounts of horizontal whitespace is very common between tokens. + if ((*CurPtr == ' ') || (*CurPtr == '\t')) { + ++CurPtr; + while ((*CurPtr == ' ') || (*CurPtr == '\t')) + ++CurPtr; + BufferPtr = CurPtr; + Result.setFlag(Token::LeadingSpace); + } + + unsigned SizeTmp, SizeTmp2; // Temporaries for use in cases below. + + // Read a character, advancing over it. + char Char = getAndAdvanceChar(CurPtr, Result); + switch (Char) { + case 0: // Null. + // Found end of file? + if (CurPtr-1 == BufferEnd) { + // Read the PP instance variable into an automatic variable, because + // LexEndOfFile will often delete 'this'. + Preprocessor *PPCache = PP; + if (LexEndOfFile(Result, CurPtr-1)) // Retreat back into the file. + return; // Got a token to return. + assert(PPCache && "Raw buffer::LexEndOfFile should return a token"); + return PPCache->Lex(Result); + } + + Diag(CurPtr-1, diag::null_in_file); + Result.setFlag(Token::LeadingSpace); + SkipWhitespace(Result, CurPtr); + goto LexNextToken; // GCC isn't tail call eliminating. + case '\n': + case '\r': + // If we are inside a preprocessor directive and we see the end of line, + // we know we are done with the directive, so return an EOM token. + if (ParsingPreprocessorDirective) { + // Done parsing the "line". + ParsingPreprocessorDirective = false; + + // Restore comment saving mode, in case it was disabled for directive. + KeepCommentMode = PP->getCommentRetentionState(); + + // Since we consumed a newline, we are back at the start of a line. + IsAtStartOfLine = true; + + Result.setKind(tok::eom); + break; + } + // The returned token is at the start of the line. + Result.setFlag(Token::StartOfLine); + // No leading whitespace seen so far. + Result.clearFlag(Token::LeadingSpace); + SkipWhitespace(Result, CurPtr); + goto LexNextToken; // GCC isn't tail call eliminating. + case ' ': + case '\t': + case '\f': + case '\v': + SkipHorizontalWhitespace: + Result.setFlag(Token::LeadingSpace); + SkipWhitespace(Result, CurPtr); + + SkipIgnoredUnits: + CurPtr = BufferPtr; + + // If the next token is obviously a // or /* */ comment, skip it efficiently + // too (without going through the big switch stmt). + if (CurPtr[0] == '/' && CurPtr[1] == '/' && !KeepCommentMode) { + SkipBCPLComment(Result, CurPtr+2); + goto SkipIgnoredUnits; + } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !KeepCommentMode) { + SkipBlockComment(Result, CurPtr+2); + goto SkipIgnoredUnits; + } else if (isHorizontalWhitespace(*CurPtr)) { + goto SkipHorizontalWhitespace; + } + goto LexNextToken; // GCC isn't tail call eliminating. + + // C99 6.4.4.1: Integer Constants. + // C99 6.4.4.2: Floating Constants. + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + return LexNumericConstant(Result, CurPtr); + + case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz"). + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + Char = getCharAndSize(CurPtr, SizeTmp); + + // Wide string literal. + if (Char == '"') + return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result), + true); + + // Wide character constant. + if (Char == '\'') + return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result)); + // FALL THROUGH, treating L like the start of an identifier. + + // C99 6.4.2: Identifiers. + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': /*'L'*/case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': + case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': + case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': + case 'v': case 'w': case 'x': case 'y': case 'z': + case '_': + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + return LexIdentifier(Result, CurPtr); + + case '$': // $ in identifiers. + if (Features.DollarIdents) { + Diag(CurPtr-1, diag::ext_dollar_in_identifier); + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + return LexIdentifier(Result, CurPtr); + } + + Result.setKind(tok::unknown); + break; + + // C99 6.4.4: Character Constants. + case '\'': + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + return LexCharConstant(Result, CurPtr); + + // C99 6.4.5: String Literals. + case '"': + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + return LexStringLiteral(Result, CurPtr, false); + + // C99 6.4.6: Punctuators. + case '?': + Result.setKind(tok::question); + break; + case '[': + Result.setKind(tok::l_square); + break; + case ']': + Result.setKind(tok::r_square); + break; + case '(': + Result.setKind(tok::l_paren); + break; + case ')': + Result.setKind(tok::r_paren); + break; + case '{': + Result.setKind(tok::l_brace); + break; + case '}': + Result.setKind(tok::r_brace); + break; + case '.': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char >= '0' && Char <= '9') { + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + + return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result)); + } else if (Features.CPlusPlus && Char == '*') { + Result.setKind(tok::periodstar); + CurPtr += SizeTmp; + } else if (Char == '.' && + getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') { + Result.setKind(tok::ellipsis); + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else { + Result.setKind(tok::period); + } + break; + case '&': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '&') { + Result.setKind(tok::ampamp); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '=') { + Result.setKind(tok::ampequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::amp); + } + break; + case '*': + if (getCharAndSize(CurPtr, SizeTmp) == '=') { + Result.setKind(tok::starequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::star); + } + break; + case '+': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '+') { + Result.setKind(tok::plusplus); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '=') { + Result.setKind(tok::plusequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::plus); + } + break; + case '-': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '-') { + Result.setKind(tok::minusminus); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '>' && Features.CPlusPlus && + getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { + Result.setKind(tok::arrowstar); // C++ ->* + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else if (Char == '>') { + Result.setKind(tok::arrow); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '=') { + Result.setKind(tok::minusequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::minus); + } + break; + case '~': + Result.setKind(tok::tilde); + break; + case '!': + if (getCharAndSize(CurPtr, SizeTmp) == '=') { + Result.setKind(tok::exclaimequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::exclaim); + } + break; + case '/': + // 6.4.9: Comments + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '/') { // BCPL comment. + if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) { + // It is common for the tokens immediately after a // comment to be + // whitespace (indentation for the next line). Instead of going through + // the big switch, handle it efficiently now. + goto SkipIgnoredUnits; + } + return; // KeepCommentMode + } else if (Char == '*') { // /**/ comment. + if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) + goto LexNextToken; // GCC isn't tail call eliminating. + return; // KeepCommentMode + } else if (Char == '=') { + Result.setKind(tok::slashequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::slash); + } + break; + case '%': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '=') { + Result.setKind(tok::percentequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Features.Digraphs && Char == '>') { + Result.setKind(tok::r_brace); // '%>' -> '}' + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Features.Digraphs && Char == ':') { + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') { + Result.setKind(tok::hashhash); // '%:%:' -> '##' + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else if (Char == '@' && Features.Microsoft) { // %:@ -> #@ -> Charize + Result.setKind(tok::hashat); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + Diag(BufferPtr, diag::charize_microsoft_ext); + } else { + Result.setKind(tok::hash); // '%:' -> '#' + + // We parsed a # character. If this occurs at the start of the line, + // it's actually the start of a preprocessing directive. Callback to + // the preprocessor to handle it. + // FIXME: -fpreprocessed mode?? + if (Result.isAtStartOfLine() && !LexingRawMode) { + BufferPtr = CurPtr; + PP->HandleDirective(Result); + + // As an optimization, if the preprocessor didn't switch lexers, tail + // recurse. + if (PP->isCurrentLexer(this)) { + // Start a new token. If this is a #include or something, the PP may + // want us starting at the beginning of the line again. If so, set + // the StartOfLine flag. + if (IsAtStartOfLine) { + Result.setFlag(Token::StartOfLine); + IsAtStartOfLine = false; + } + goto LexNextToken; // GCC isn't tail call eliminating. + } + + return PP->Lex(Result); + } + } + } else { + Result.setKind(tok::percent); + } + break; + case '<': + Char = getCharAndSize(CurPtr, SizeTmp); + if (ParsingFilename) { + return LexAngledStringLiteral(Result, CurPtr+SizeTmp); + } else if (Char == '<' && + getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { + Result.setKind(tok::lesslessequal); + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else if (Char == '<') { + Result.setKind(tok::lessless); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '=') { + Result.setKind(tok::lessequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Features.Digraphs && Char == ':') { + Result.setKind(tok::l_square); // '<:' -> '[' + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Features.Digraphs && Char == '%') { + Result.setKind(tok::l_brace); // '<%' -> '{' + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::less); + } + break; + case '>': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '=') { + Result.setKind(tok::greaterequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '>' && + getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { + Result.setKind(tok::greatergreaterequal); + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else if (Char == '>') { + Result.setKind(tok::greatergreater); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::greater); + } + break; + case '^': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '=') { + Result.setKind(tok::caretequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::caret); + } + break; + case '|': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '=') { + Result.setKind(tok::pipeequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '|') { + Result.setKind(tok::pipepipe); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::pipe); + } + break; + case ':': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Features.Digraphs && Char == '>') { + Result.setKind(tok::r_square); // ':>' -> ']' + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Features.CPlusPlus && Char == ':') { + Result.setKind(tok::coloncolon); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::colon); + } + break; + case ';': + Result.setKind(tok::semi); + break; + case '=': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '=') { + Result.setKind(tok::equalequal); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::equal); + } + break; + case ',': + Result.setKind(tok::comma); + break; + case '#': + Char = getCharAndSize(CurPtr, SizeTmp); + if (Char == '#') { + Result.setKind(tok::hashhash); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else if (Char == '@' && Features.Microsoft) { // #@ -> Charize + Result.setKind(tok::hashat); + Diag(BufferPtr, diag::charize_microsoft_ext); + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + } else { + Result.setKind(tok::hash); + // We parsed a # character. If this occurs at the start of the line, + // it's actually the start of a preprocessing directive. Callback to + // the preprocessor to handle it. + // FIXME: -fpreprocessed mode?? + if (Result.isAtStartOfLine() && !LexingRawMode) { + BufferPtr = CurPtr; + PP->HandleDirective(Result); + + // As an optimization, if the preprocessor didn't switch lexers, tail + // recurse. + if (PP->isCurrentLexer(this)) { + // Start a new token. If this is a #include or something, the PP may + // want us starting at the beginning of the line again. If so, set + // the StartOfLine flag. + if (IsAtStartOfLine) { + Result.setFlag(Token::StartOfLine); + IsAtStartOfLine = false; + } + goto LexNextToken; // GCC isn't tail call eliminating. + } + return PP->Lex(Result); + } + } + break; + + case '@': + // Objective C support. + if (CurPtr[-1] == '@' && Features.ObjC1) + Result.setKind(tok::at); + else + Result.setKind(tok::unknown); + break; + + case '\\': + // FIXME: UCN's. + // FALL THROUGH. + default: + Result.setKind(tok::unknown); + break; + } + + // Notify MIOpt that we read a non-whitespace/non-comment token. + MIOpt.ReadToken(); + + // Update the location of token as well as BufferPtr. + FormTokenWithChars(Result, CurPtr); +} diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp new file mode 100644 index 00000000000..aa0b831af90 --- /dev/null +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -0,0 +1,691 @@ +//===--- LiteralSupport.cpp - Code to parse and process literals ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the NumericLiteralParser, CharLiteralParser, and +// StringLiteralParser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; + +/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's +/// not valid. +static int HexDigitValue(char C) { + if (C >= '0' && C <= '9') return C-'0'; + if (C >= 'a' && C <= 'f') return C-'a'+10; + if (C >= 'A' && C <= 'F') return C-'A'+10; + return -1; +} + +/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in +/// either a character or a string literal. +static unsigned ProcessCharEscape(const char *&ThisTokBuf, + const char *ThisTokEnd, bool &HadError, + SourceLocation Loc, bool IsWide, + Preprocessor &PP) { + // Skip the '\' char. + ++ThisTokBuf; + + // We know that this character can't be off the end of the buffer, because + // that would have been \", which would not have been the end of string. + unsigned ResultChar = *ThisTokBuf++; + switch (ResultChar) { + // These map to themselves. + case '\\': case '\'': case '"': case '?': break; + + // These have fixed mappings. + case 'a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + ResultChar = 7; + break; + case 'b': + ResultChar = 8; + break; + case 'e': + PP.Diag(Loc, diag::ext_nonstandard_escape, "e"); + ResultChar = 27; + break; + case 'f': + ResultChar = 12; + break; + case 'n': + ResultChar = 10; + break; + case 'r': + ResultChar = 13; + break; + case 't': + ResultChar = 9; + break; + case 'v': + ResultChar = 11; + break; + + //case 'u': case 'U': // FIXME: UCNs. + case 'x': { // Hex escape. + ResultChar = 0; + if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) { + PP.Diag(Loc, diag::err_hex_escape_no_digits); + HadError = 1; + break; + } + + // Hex escapes are a maximal series of hex digits. + bool Overflow = false; + for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) { + int CharVal = HexDigitValue(ThisTokBuf[0]); + if (CharVal == -1) break; + Overflow |= (ResultChar & 0xF0000000) ? true : false; // About to shift out a digit? + ResultChar <<= 4; + ResultChar |= CharVal; + } + + // See if any bits will be truncated when evaluated as a character. + unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide); + + if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { + Overflow = true; + ResultChar &= ~0U >> (32-CharWidth); + } + + // Check for overflow. + if (Overflow) // Too many digits to fit in + PP.Diag(Loc, diag::warn_hex_escape_too_large); + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': { + // Octal escapes. + --ThisTokBuf; + ResultChar = 0; + + // Octal escapes are a series of octal digits with maximum length 3. + // "\0123" is a two digit sequence equal to "\012" "3". + unsigned NumDigits = 0; + do { + ResultChar <<= 3; + ResultChar |= *ThisTokBuf++ - '0'; + ++NumDigits; + } while (ThisTokBuf != ThisTokEnd && NumDigits < 3 && + ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7'); + + // Check for overflow. Reject '\777', but not L'\777'. + unsigned CharWidth = PP.getTargetInfo().getCharWidth(IsWide); + + if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { + PP.Diag(Loc, diag::warn_octal_escape_too_large); + ResultChar &= ~0U >> (32-CharWidth); + } + break; + } + + // Otherwise, these are not valid escapes. + case '(': case '{': case '[': case '%': + // GCC accepts these as extensions. We warn about them as such though. + if (!PP.getLangOptions().NoExtensions) { + PP.Diag(Loc, diag::ext_nonstandard_escape, + std::string()+(char)ResultChar); + break; + } + // FALL THROUGH. + default: + if (isgraph(ThisTokBuf[0])) { + PP.Diag(Loc, diag::ext_unknown_escape, std::string()+(char)ResultChar); + } else { + PP.Diag(Loc, diag::ext_unknown_escape, "x"+llvm::utohexstr(ResultChar)); + } + break; + } + + return ResultChar; +} + + + + +/// integer-constant: [C99 6.4.4.1] +/// decimal-constant integer-suffix +/// octal-constant integer-suffix +/// hexadecimal-constant integer-suffix +/// decimal-constant: +/// nonzero-digit +/// decimal-constant digit +/// octal-constant: +/// 0 +/// octal-constant octal-digit +/// hexadecimal-constant: +/// hexadecimal-prefix hexadecimal-digit +/// hexadecimal-constant hexadecimal-digit +/// hexadecimal-prefix: one of +/// 0x 0X +/// integer-suffix: +/// unsigned-suffix [long-suffix] +/// unsigned-suffix [long-long-suffix] +/// long-suffix [unsigned-suffix] +/// long-long-suffix [unsigned-sufix] +/// nonzero-digit: +/// 1 2 3 4 5 6 7 8 9 +/// octal-digit: +/// 0 1 2 3 4 5 6 7 +/// hexadecimal-digit: +/// 0 1 2 3 4 5 6 7 8 9 +/// a b c d e f +/// A B C D E F +/// unsigned-suffix: one of +/// u U +/// long-suffix: one of +/// l L +/// long-long-suffix: one of +/// ll LL +/// +/// floating-constant: [C99 6.4.4.2] +/// TODO: add rules... +/// + +NumericLiteralParser:: +NumericLiteralParser(const char *begin, const char *end, + SourceLocation TokLoc, Preprocessor &pp) + : PP(pp), ThisTokBegin(begin), ThisTokEnd(end) { + s = DigitsBegin = begin; + saw_exponent = false; + saw_period = false; + isLong = false; + isUnsigned = false; + isLongLong = false; + isFloat = false; + isImaginary = false; + hadError = false; + + if (*s == '0') { // parse radix + s++; + if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) { + s++; + radix = 16; + DigitsBegin = s; + s = SkipHexDigits(s); + if (s == ThisTokEnd) { + // Done. + } else if (*s == '.') { + s++; + saw_period = true; + s = SkipHexDigits(s); + } + // A binary exponent can appear with or with a '.'. If dotted, the + // binary exponent is required. + if ((*s == 'p' || *s == 'P') && PP.getLangOptions().HexFloats) { + s++; + saw_exponent = true; + if (*s == '+' || *s == '-') s++; // sign + const char *first_non_digit = SkipDigits(s); + if (first_non_digit == s) { + Diag(TokLoc, diag::err_exponent_has_no_digits); + return; + } else { + s = first_non_digit; + } + } else if (saw_period) { + Diag(TokLoc, diag::err_hexconstant_requires_exponent); + return; + } + } else if (*s == 'b' || *s == 'B') { + // 0b101010 is a GCC extension. + ++s; + radix = 2; + DigitsBegin = s; + s = SkipBinaryDigits(s); + if (s == ThisTokEnd) { + // Done. + } else if (isxdigit(*s)) { + Diag(TokLoc, diag::err_invalid_binary_digit, std::string(s, s+1)); + return; + } + PP.Diag(TokLoc, diag::ext_binary_literal); + } else { + // For now, the radix is set to 8. If we discover that we have a + // floating point constant, the radix will change to 10. Octal floating + // point constants are not permitted (only decimal and hexadecimal). + radix = 8; + DigitsBegin = s; + s = SkipOctalDigits(s); + if (s == ThisTokEnd) { + // Done. + } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { + TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin); + Diag(TokLoc, diag::err_invalid_octal_digit, std::string(s, s+1)); + return; + } else if (*s == '.') { + s++; + radix = 10; + saw_period = true; + s = SkipDigits(s); + } + if (*s == 'e' || *s == 'E') { // exponent + s++; + radix = 10; + saw_exponent = true; + if (*s == '+' || *s == '-') s++; // sign + const char *first_non_digit = SkipDigits(s); + if (first_non_digit == s) { + Diag(TokLoc, diag::err_exponent_has_no_digits); + return; + } else { + s = first_non_digit; + } + } + } + } else { // the first digit is non-zero + radix = 10; + s = SkipDigits(s); + if (s == ThisTokEnd) { + // Done. + } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { + Diag(TokLoc, diag::err_invalid_decimal_digit, std::string(s, s+1)); + return; + } else if (*s == '.') { + s++; + saw_period = true; + s = SkipDigits(s); + } + if (*s == 'e' || *s == 'E') { // exponent + s++; + saw_exponent = true; + if (*s == '+' || *s == '-') s++; // sign + const char *first_non_digit = SkipDigits(s); + if (first_non_digit == s) { + Diag(TokLoc, diag::err_exponent_has_no_digits); + return; + } else { + s = first_non_digit; + } + } + } + + SuffixBegin = s; + + // Parse the suffix. At this point we can classify whether we have an FP or + // integer constant. + bool isFPConstant = isFloatingLiteral(); + + // Loop over all of the characters of the suffix. If we see something bad, + // we break out of the loop. + for (; s != ThisTokEnd; ++s) { + switch (*s) { + case 'f': // FP Suffix for "float" + case 'F': + if (!isFPConstant) break; // Error for integer constant. + if (isFloat || isLong) break; // FF, LF invalid. + isFloat = true; + continue; // Success. + case 'u': + case 'U': + if (isFPConstant) break; // Error for floating constant. + if (isUnsigned) break; // Cannot be repeated. + isUnsigned = true; + continue; // Success. + case 'l': + case 'L': + if (isLong || isLongLong) break; // Cannot be repeated. + if (isFloat) break; // LF invalid. + + // Check for long long. The L's need to be adjacent and the same case. + if (s+1 != ThisTokEnd && s[1] == s[0]) { + if (isFPConstant) break; // long long invalid for floats. + isLongLong = true; + ++s; // Eat both of them. + } else { + isLong = true; + } + continue; // Success. + case 'i': + case 'I': + case 'j': + case 'J': + if (isImaginary) break; // Cannot be repeated. + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), + diag::ext_imaginary_constant); + isImaginary = true; + continue; // Success. + } + // If we reached here, there was an error. + break; + } + + // Report an error if there are any. + if (s != ThisTokEnd) { + TokLoc = PP.AdvanceToTokenCharacter(TokLoc, s-begin); + Diag(TokLoc, isFPConstant ? diag::err_invalid_suffix_float_constant : + diag::err_invalid_suffix_integer_constant, + std::string(SuffixBegin, ThisTokEnd)); + return; + } +} + +/// GetIntegerValue - Convert this numeric literal value to an APInt that +/// matches Val's input width. If there is an overflow, set Val to the low bits +/// of the result and return true. Otherwise, return false. +bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { + Val = 0; + s = DigitsBegin; + + llvm::APInt RadixVal(Val.getBitWidth(), radix); + llvm::APInt CharVal(Val.getBitWidth(), 0); + llvm::APInt OldVal = Val; + + bool OverflowOccurred = false; + while (s < SuffixBegin) { + unsigned C = HexDigitValue(*s++); + + // If this letter is out of bound for this radix, reject it. + assert(C < radix && "NumericLiteralParser ctor should have rejected this"); + + CharVal = C; + + // Add the digit to the value in the appropriate radix. If adding in digits + // made the value smaller, then this overflowed. + OldVal = Val; + + // Multiply by radix, did overflow occur on the multiply? + Val *= RadixVal; + OverflowOccurred |= Val.udiv(RadixVal) != OldVal; + + OldVal = Val; + // Add value, did overflow occur on the value? + Val += CharVal; + OverflowOccurred |= Val.ult(OldVal); + OverflowOccurred |= Val.ult(CharVal); + } + return OverflowOccurred; +} + +llvm::APFloat NumericLiteralParser:: +GetFloatValue(const llvm::fltSemantics &Format, bool* isExact) { + using llvm::APFloat; + + llvm::SmallVector floatChars; + for (unsigned i = 0, n = ThisTokEnd-ThisTokBegin; i != n; ++i) + floatChars.push_back(ThisTokBegin[i]); + + floatChars.push_back('\0'); + + APFloat V (Format, APFloat::fcZero, false); + APFloat::opStatus status; + + status = V.convertFromString(&floatChars[0],APFloat::rmNearestTiesToEven); + + if (isExact) + *isExact = status == APFloat::opOK; + + return V; +} + +void NumericLiteralParser::Diag(SourceLocation Loc, unsigned DiagID, + const std::string &M) { + PP.Diag(Loc, DiagID, M); + hadError = true; +} + + +CharLiteralParser::CharLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP) { + // At this point we know that the character matches the regex "L?'.*'". + HadError = false; + Value = 0; + + // Determine if this is a wide character. + IsWide = begin[0] == 'L'; + if (IsWide) ++begin; + + // Skip over the entry quote. + assert(begin[0] == '\'' && "Invalid token lexed"); + ++begin; + + // FIXME: This assumes that 'int' is 32-bits in overflow calculation, and the + // size of "value". + assert(PP.getTargetInfo().getIntWidth() == 32 && + "Assumes sizeof(int) == 4 for now"); + // FIXME: This assumes that wchar_t is 32-bits for now. + assert(PP.getTargetInfo().getWCharWidth() == 32 && + "Assumes sizeof(wchar_t) == 4 for now"); + // FIXME: This extensively assumes that 'char' is 8-bits. + assert(PP.getTargetInfo().getCharWidth() == 8 && + "Assumes char is 8 bits"); + + bool isFirstChar = true; + bool isMultiChar = false; + while (begin[0] != '\'') { + unsigned ResultChar; + if (begin[0] != '\\') // If this is a normal character, consume it. + ResultChar = *begin++; + else // Otherwise, this is an escape character. + ResultChar = ProcessCharEscape(begin, end, HadError, Loc, IsWide, PP); + + // If this is a multi-character constant (e.g. 'abc'), handle it. These are + // implementation defined (C99 6.4.4.4p10). + if (!isFirstChar) { + // If this is the second character being processed, do special handling. + if (!isMultiChar) { + isMultiChar = true; + + // Warn about discarding the top bits for multi-char wide-character + // constants (L'abcd'). + if (IsWide) + PP.Diag(Loc, diag::warn_extraneous_wide_char_constant); + } + + if (IsWide) { + // Emulate GCC's (unintentional?) behavior: L'ab' -> L'b'. + Value = 0; + } else { + // Narrow character literals act as though their value is concatenated + // in this implementation. + if (((Value << 8) >> 8) != Value) + PP.Diag(Loc, diag::warn_char_constant_too_large); + Value <<= 8; + } + } + + Value += ResultChar; + isFirstChar = false; + } + + // If this is a single narrow character, sign extend it (e.g. '\xFF' is "-1") + // if 'char' is signed for this target (C99 6.4.4.4p10). Note that multiple + // character constants are not sign extended in the this implementation: + // '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC. + if (!IsWide && !isMultiChar && (Value & 128) && + PP.getTargetInfo().isCharSigned()) + Value = (signed char)Value; +} + + +/// string-literal: [C99 6.4.5] +/// " [s-char-sequence] " +/// L" [s-char-sequence] " +/// s-char-sequence: +/// s-char +/// s-char-sequence s-char +/// s-char: +/// any source character except the double quote ", +/// backslash \, or newline character +/// escape-character +/// universal-character-name +/// escape-character: [C99 6.4.4.4] +/// \ escape-code +/// universal-character-name +/// escape-code: +/// character-escape-code +/// octal-escape-code +/// hex-escape-code +/// character-escape-code: one of +/// n t b r f v a +/// \ ' " ? +/// octal-escape-code: +/// octal-digit +/// octal-digit octal-digit +/// octal-digit octal-digit octal-digit +/// hex-escape-code: +/// x hex-digit +/// hex-escape-code hex-digit +/// universal-character-name: +/// \u hex-quad +/// \U hex-quad hex-quad +/// hex-quad: +/// hex-digit hex-digit hex-digit hex-digit +/// +StringLiteralParser:: +StringLiteralParser(const Token *StringToks, unsigned NumStringToks, + Preprocessor &pp, TargetInfo &t) + : PP(pp), Target(t) { + // Scan all of the string portions, remember the max individual token length, + // computing a bound on the concatenated string length, and see whether any + // piece is a wide-string. If any of the string portions is a wide-string + // literal, the result is a wide-string literal [C99 6.4.5p4]. + MaxTokenLength = StringToks[0].getLength(); + SizeBound = StringToks[0].getLength()-2; // -2 for "". + AnyWide = StringToks[0].is(tok::wide_string_literal); + + hadError = false; + + // Implement Translation Phase #6: concatenation of string literals + /// (C99 5.1.1.2p1). The common case is only one string fragment. + for (unsigned i = 1; i != NumStringToks; ++i) { + // The string could be shorter than this if it needs cleaning, but this is a + // reasonable bound, which is all we need. + SizeBound += StringToks[i].getLength()-2; // -2 for "". + + // Remember maximum string piece length. + if (StringToks[i].getLength() > MaxTokenLength) + MaxTokenLength = StringToks[i].getLength(); + + // Remember if we see any wide strings. + AnyWide |= StringToks[i].is(tok::wide_string_literal); + } + + + // Include space for the null terminator. + ++SizeBound; + + // TODO: K&R warning: "traditional C rejects string constant concatenation" + + // Get the width in bytes of wchar_t. If no wchar_t strings are used, do not + // query the target. As such, wchar_tByteWidth is only valid if AnyWide=true. + wchar_tByteWidth = ~0U; + if (AnyWide) { + wchar_tByteWidth = Target.getWCharWidth(); + assert((wchar_tByteWidth & 7) == 0 && "Assumes wchar_t is byte multiple!"); + wchar_tByteWidth /= 8; + } + + // The output buffer size needs to be large enough to hold wide characters. + // This is a worst-case assumption which basically corresponds to L"" "long". + if (AnyWide) + SizeBound *= wchar_tByteWidth; + + // Size the temporary buffer to hold the result string data. + ResultBuf.resize(SizeBound); + + // Likewise, but for each string piece. + llvm::SmallString<512> TokenBuf; + TokenBuf.resize(MaxTokenLength); + + // Loop over all the strings, getting their spelling, and expanding them to + // wide strings as appropriate. + ResultPtr = &ResultBuf[0]; // Next byte to fill in. + + Pascal = false; + + for (unsigned i = 0, e = NumStringToks; i != e; ++i) { + const char *ThisTokBuf = &TokenBuf[0]; + // Get the spelling of the token, which eliminates trigraphs, etc. We know + // that ThisTokBuf points to a buffer that is big enough for the whole token + // and 'spelled' tokens can only shrink. + unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf); + const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote. + + // TODO: Input character set mapping support. + + // Skip L marker for wide strings. + bool ThisIsWide = false; + if (ThisTokBuf[0] == 'L') { + ++ThisTokBuf; + ThisIsWide = true; + } + + assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?"); + ++ThisTokBuf; + + // Check if this is a pascal string + if (pp.getLangOptions().PascalStrings && ThisTokBuf + 1 != ThisTokEnd && + ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') { + + // If the \p sequence is found in the first token, we have a pascal string + // Otherwise, if we already have a pascal string, ignore the first \p + if (i == 0) { + ++ThisTokBuf; + Pascal = true; + } else if (Pascal) + ThisTokBuf += 2; + } + + while (ThisTokBuf != ThisTokEnd) { + // Is this a span of non-escape characters? + if (ThisTokBuf[0] != '\\') { + const char *InStart = ThisTokBuf; + do { + ++ThisTokBuf; + } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\'); + + // Copy the character span over. + unsigned Len = ThisTokBuf-InStart; + if (!AnyWide) { + memcpy(ResultPtr, InStart, Len); + ResultPtr += Len; + } else { + // Note: our internal rep of wide char tokens is always little-endian. + for (; Len; --Len, ++InStart) { + *ResultPtr++ = InStart[0]; + // Add zeros at the end. + for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) + *ResultPtr++ = 0; + } + } + continue; + } + + // Otherwise, this is an escape character. Process it. + unsigned ResultChar = ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError, + StringToks[i].getLocation(), + ThisIsWide, PP); + + // Note: our internal rep of wide char tokens is always little-endian. + *ResultPtr++ = ResultChar & 0xFF; + + if (AnyWide) { + for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) + *ResultPtr++ = ResultChar >> i*8; + } + } + } + + // Add zero terminator. + *ResultPtr = 0; + if (AnyWide) { + for (unsigned i = 1, e = wchar_tByteWidth; i != e; ++i) + *ResultPtr++ = 0; + } + + if (Pascal) + ResultBuf[0] = ResultPtr-&ResultBuf[0]-1; +} diff --git a/clang/lib/Lex/MacroArgs.cpp b/clang/lib/Lex/MacroArgs.cpp new file mode 100644 index 00000000000..a26e50eb762 --- /dev/null +++ b/clang/lib/Lex/MacroArgs.cpp @@ -0,0 +1,225 @@ +//===--- TokenLexer.cpp - Lex from a token stream -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TokenLexer interface. +// +//===----------------------------------------------------------------------===// + +#include "MacroArgs.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Diagnostic.h" +using namespace clang; + +/// MacroArgs ctor function - This destroys the vector passed in. +MacroArgs *MacroArgs::create(const MacroInfo *MI, + const Token *UnexpArgTokens, + unsigned NumToks, bool VarargsElided) { + assert(MI->isFunctionLike() && + "Can't have args for an object-like macro!"); + + // Allocate memory for the MacroArgs object with the lexer tokens at the end. + MacroArgs *Result = (MacroArgs*)malloc(sizeof(MacroArgs) + + NumToks*sizeof(Token)); + // Construct the macroargs object. + new (Result) MacroArgs(NumToks, VarargsElided); + + // Copy the actual unexpanded tokens to immediately after the result ptr. + if (NumToks) + memcpy(const_cast(Result->getUnexpArgument(0)), + UnexpArgTokens, NumToks*sizeof(Token)); + + return Result; +} + +/// destroy - Destroy and deallocate the memory for this object. +/// +void MacroArgs::destroy() { + // Run the dtor to deallocate the vectors. + this->~MacroArgs(); + // Release the memory for the object. + free(this); +} + + +/// getArgLength - Given a pointer to an expanded or unexpanded argument, +/// return the number of tokens, not counting the EOF, that make up the +/// argument. +unsigned MacroArgs::getArgLength(const Token *ArgPtr) { + unsigned NumArgTokens = 0; + for (; ArgPtr->isNot(tok::eof); ++ArgPtr) + ++NumArgTokens; + return NumArgTokens; +} + + +/// getUnexpArgument - Return the unexpanded tokens for the specified formal. +/// +const Token *MacroArgs::getUnexpArgument(unsigned Arg) const { + // The unexpanded argument tokens start immediately after the MacroArgs object + // in memory. + const Token *Start = (const Token *)(this+1); + const Token *Result = Start; + // Scan to find Arg. + for (; Arg; ++Result) { + assert(Result < Start+NumUnexpArgTokens && "Invalid arg #"); + if (Result->is(tok::eof)) + --Arg; + } + return Result; +} + + +/// ArgNeedsPreexpansion - If we can prove that the argument won't be affected +/// by pre-expansion, return false. Otherwise, conservatively return true. +bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok, + Preprocessor &PP) const { + // If there are no identifiers in the argument list, or if the identifiers are + // known to not be macros, pre-expansion won't modify it. + for (; ArgTok->isNot(tok::eof); ++ArgTok) + if (IdentifierInfo *II = ArgTok->getIdentifierInfo()) { + if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled()) + // Return true even though the macro could be a function-like macro + // without a following '(' token. + return true; + } + return false; +} + +/// getPreExpArgument - Return the pre-expanded form of the specified +/// argument. +const std::vector & +MacroArgs::getPreExpArgument(unsigned Arg, Preprocessor &PP) { + assert(Arg < NumUnexpArgTokens && "Invalid argument number!"); + + // If we have already computed this, return it. + if (PreExpArgTokens.empty()) + PreExpArgTokens.resize(NumUnexpArgTokens); + + std::vector &Result = PreExpArgTokens[Arg]; + if (!Result.empty()) return Result; + + const Token *AT = getUnexpArgument(Arg); + unsigned NumToks = getArgLength(AT)+1; // Include the EOF. + + // Otherwise, we have to pre-expand this argument, populating Result. To do + // this, we set up a fake TokenLexer to lex from the unexpanded argument + // list. With this installed, we lex expanded tokens until we hit the EOF + // token at the end of the unexp list. + PP.EnterTokenStream(AT, NumToks, false /*disable expand*/, + false /*owns tokens*/); + + // Lex all of the macro-expanded tokens into Result. + do { + Result.push_back(Token()); + PP.Lex(Result.back()); + } while (Result.back().isNot(tok::eof)); + + // Pop the token stream off the top of the stack. We know that the internal + // pointer inside of it is to the "end" of the token stream, but the stack + // will not otherwise be popped until the next token is lexed. The problem is + // that the token may be lexed sometime after the vector of tokens itself is + // destroyed, which would be badness. + PP.RemoveTopOfLexerStack(); + return Result; +} + + +/// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of +/// tokens into the literal string token that should be produced by the C # +/// preprocessor operator. If Charify is true, then it should be turned into +/// a character literal for the Microsoft charize (#@) extension. +/// +Token MacroArgs::StringifyArgument(const Token *ArgToks, + Preprocessor &PP, bool Charify) { + Token Tok; + Tok.startToken(); + Tok.setKind(tok::string_literal); + + const Token *ArgTokStart = ArgToks; + + // Stringify all the tokens. + std::string Result = "\""; + // FIXME: Optimize this loop to not use std::strings. + bool isFirst = true; + for (; ArgToks->isNot(tok::eof); ++ArgToks) { + const Token &Tok = *ArgToks; + if (!isFirst && (Tok.hasLeadingSpace() || Tok.isAtStartOfLine())) + Result += ' '; + isFirst = false; + + // If this is a string or character constant, escape the token as specified + // by 6.10.3.2p2. + if (Tok.is(tok::string_literal) || // "foo" + Tok.is(tok::wide_string_literal) || // L"foo" + Tok.is(tok::char_constant)) { // 'x' and L'x'. + Result += Lexer::Stringify(PP.getSpelling(Tok)); + } else { + // Otherwise, just append the token. + Result += PP.getSpelling(Tok); + } + } + + // If the last character of the string is a \, and if it isn't escaped, this + // is an invalid string literal, diagnose it as specified in C99. + if (Result[Result.size()-1] == '\\') { + // Count the number of consequtive \ characters. If even, then they are + // just escaped backslashes, otherwise it's an error. + unsigned FirstNonSlash = Result.size()-2; + // Guaranteed to find the starting " if nothing else. + while (Result[FirstNonSlash] == '\\') + --FirstNonSlash; + if ((Result.size()-1-FirstNonSlash) & 1) { + // Diagnose errors for things like: #define F(X) #X / F(\) + PP.Diag(ArgToks[-1], diag::pp_invalid_string_literal); + Result.erase(Result.end()-1); // remove one of the \'s. + } + } + Result += '"'; + + // If this is the charify operation and the result is not a legal character + // constant, diagnose it. + if (Charify) { + // First step, turn double quotes into single quotes: + Result[0] = '\''; + Result[Result.size()-1] = '\''; + + // Check for bogus character. + bool isBad = false; + if (Result.size() == 3) { + isBad = Result[1] == '\''; // ''' is not legal. '\' already fixed above. + } else { + isBad = (Result.size() != 4 || Result[1] != '\\'); // Not '\x' + } + + if (isBad) { + PP.Diag(ArgTokStart[0], diag::err_invalid_character_to_charify); + Result = "' '"; // Use something arbitrary, but legal. + } + } + + Tok.setLength(Result.size()); + Tok.setLocation(PP.CreateString(&Result[0], Result.size())); + return Tok; +} + +/// getStringifiedArgument - Compute, cache, and return the specified argument +/// that has been 'stringified' as required by the # operator. +const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, + Preprocessor &PP) { + assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!"); + if (StringifiedArgs.empty()) { + StringifiedArgs.resize(getNumArguments()); + memset(&StringifiedArgs[0], 0, + sizeof(StringifiedArgs[0])*getNumArguments()); + } + if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) + StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP); + return StringifiedArgs[ArgNo]; +} diff --git a/clang/lib/Lex/MacroArgs.h b/clang/lib/Lex/MacroArgs.h new file mode 100644 index 00000000000..4b22fa18aa8 --- /dev/null +++ b/clang/lib/Lex/MacroArgs.h @@ -0,0 +1,109 @@ +//===--- MacroArgs.h - Formal argument info for Macros ----------*- 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 MacroArgs interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_MACROARGS_H +#define LLVM_CLANG_MACROARGS_H + +#include + +namespace clang { + class MacroInfo; + class Preprocessor; + class Token; + +/// MacroArgs - An instance of this class captures information about +/// the formal arguments specified to a function-like macro invocation. +class MacroArgs { + /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the + /// arguments. All of the actual argument tokens are allocated immediately + /// after the MacroArgs object in memory. This is all of the arguments + /// concatenated together, with 'EOF' markers at the end of each argument. + unsigned NumUnexpArgTokens; + + /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty + /// if not yet computed. This includes the EOF marker at the end of the + /// stream. + std::vector > PreExpArgTokens; + + /// StringifiedArgs - This contains arguments in 'stringified' form. If the + /// stringified form of an argument has not yet been computed, this is empty. + std::vector StringifiedArgs; + + /// VarargsElided - True if this is a C99 style varargs macro invocation and + /// there was no argument specified for the "..." argument. If the argument + /// was specified (even empty) or this isn't a C99 style varargs function, or + /// if in strict mode and the C99 varargs macro had only a ... argument, this + /// is false. + bool VarargsElided; + + MacroArgs(unsigned NumToks, bool varargsElided) + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {} + ~MacroArgs() {} +public: + /// MacroArgs ctor function - Create a new MacroArgs object with the specified + /// macro and argument info. + static MacroArgs *create(const MacroInfo *MI, + const Token *UnexpArgTokens, + unsigned NumArgTokens, bool VarargsElided); + + /// destroy - Destroy and deallocate the memory for this object. + /// + void destroy(); + + /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected + /// by pre-expansion, return false. Otherwise, conservatively return true. + bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const; + + /// getUnexpArgument - Return a pointer to the first token of the unexpanded + /// token list for the specified formal. + /// + const Token *getUnexpArgument(unsigned Arg) const; + + /// getArgLength - Given a pointer to an expanded or unexpanded argument, + /// return the number of tokens, not counting the EOF, that make up the + /// argument. + static unsigned getArgLength(const Token *ArgPtr); + + /// getPreExpArgument - Return the pre-expanded form of the specified + /// argument. + const std::vector & + getPreExpArgument(unsigned Arg, Preprocessor &PP); + + /// getStringifiedArgument - Compute, cache, and return the specified argument + /// that has been 'stringified' as required by the # operator. + const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP); + + /// getNumArguments - Return the number of arguments passed into this macro + /// invocation. + unsigned getNumArguments() const { return NumUnexpArgTokens; } + + + /// isVarargsElidedUse - Return true if this is a C99 style varargs macro + /// invocation and there was no argument specified for the "..." argument. If + /// the argument was specified (even empty) or this isn't a C99 style varargs + /// function, or if in strict mode and the C99 varargs macro had only a ... + /// argument, this returns false. + bool isVarargsElidedUse() const { return VarargsElided; } + + /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of + /// tokens into the literal string token that should be produced by the C # + /// preprocessor operator. If Charify is true, then it should be turned into + /// a character literal for the Microsoft charize (#@) extension. + /// + static Token StringifyArgument(const Token *ArgToks, + Preprocessor &PP, bool Charify = false); +}; + +} // end namespace clang + +#endif diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp new file mode 100644 index 00000000000..de19ff502a6 --- /dev/null +++ b/clang/lib/Lex/MacroInfo.cpp @@ -0,0 +1,70 @@ +//===--- MacroInfo.cpp - Information about #defined identifiers -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MacroInfo interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Preprocessor.h" +using namespace clang; + +MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { + IsFunctionLike = false; + IsC99Varargs = false; + IsGNUVarargs = false; + IsBuiltinMacro = false; + IsDisabled = false; + IsUsed = true; + + ArgumentList = 0; + NumArguments = 0; +} + +/// isIdenticalTo - Return true if the specified macro definition is equal to +/// this macro in spelling, arguments, and whitespace. This is used to emit +/// duplicate definition warnings. This implements the rules in C99 6.10.3. +/// +bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const { + // Check # tokens in replacement, number of args, and various flags all match. + if (ReplacementTokens.size() != Other.ReplacementTokens.size() || + getNumArgs() != Other.getNumArgs() || + isFunctionLike() != Other.isFunctionLike() || + isC99Varargs() != Other.isC99Varargs() || + isGNUVarargs() != Other.isGNUVarargs()) + return false; + + // Check arguments. + for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end(); + I != E; ++I, ++OI) + if (*I != *OI) return false; + + // Check all the tokens. + for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) { + const Token &A = ReplacementTokens[i]; + const Token &B = Other.ReplacementTokens[i]; + if (A.getKind() != B.getKind() || + A.isAtStartOfLine() != B.isAtStartOfLine() || + A.hasLeadingSpace() != B.hasLeadingSpace()) + return false; + + // If this is an identifier, it is easy. + if (A.getIdentifierInfo() || B.getIdentifierInfo()) { + if (A.getIdentifierInfo() != B.getIdentifierInfo()) + return false; + continue; + } + + // Otherwise, check the spelling. + if (PP.getSpelling(A) != PP.getSpelling(B)) + return false; + } + + return true; +} diff --git a/clang/lib/Lex/Makefile b/clang/lib/Lex/Makefile new file mode 100644 index 00000000000..187448c9922 --- /dev/null +++ b/clang/lib/Lex/Makefile @@ -0,0 +1,28 @@ +##===- clang/lib/Lex/Makefile ------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Lexer library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +include $(LEVEL)/Makefile.config + +LIBRARYNAME := clangLex +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +ifeq ($(ARCH),PowerPC) +CXXFLAGS += -maltivec +endif + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp new file mode 100644 index 00000000000..b24f5b63760 --- /dev/null +++ b/clang/lib/Lex/PPDirectives.cpp @@ -0,0 +1,1153 @@ +//===--- PPDirectives.cpp - Directive Handling for Preprocessor -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements # directive processing for the Preprocessor. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Utility Methods for Preprocessor Directive Handling. +//===----------------------------------------------------------------------===// + +/// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the +/// current line until the tok::eom token is found. +void Preprocessor::DiscardUntilEndOfDirective() { + Token Tmp; + do { + LexUnexpandedToken(Tmp); + } while (Tmp.isNot(tok::eom)); +} + +/// isCXXNamedOperator - Returns "true" if the token is a named operator in C++. +static bool isCXXNamedOperator(const std::string &Spelling) { + return Spelling == "and" || Spelling == "bitand" || Spelling == "bitor" || + Spelling == "compl" || Spelling == "not" || Spelling == "not_eq" || + Spelling == "or" || Spelling == "xor"; +} + +/// ReadMacroName - Lex and validate a macro name, which occurs after a +/// #define or #undef. This sets the token kind to eom and discards the rest +/// of the macro line if the macro name is invalid. isDefineUndef is 1 if +/// this is due to a a #define, 2 if #undef directive, 0 if it is something +/// else (e.g. #ifdef). +void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { + // Read the token, don't allow macro expansion on it. + LexUnexpandedToken(MacroNameTok); + + // Missing macro name? + if (MacroNameTok.is(tok::eom)) + return Diag(MacroNameTok, diag::err_pp_missing_macro_name); + + IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); + if (II == 0) { + std::string Spelling = getSpelling(MacroNameTok); + if (isCXXNamedOperator(Spelling)) + // C++ 2.5p2: Alternative tokens behave the same as its primary token + // except for their spellings. + Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name, Spelling); + else + Diag(MacroNameTok, diag::err_pp_macro_not_identifier); + // Fall through on error. + } else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) { + // Error if defining "defined": C99 6.10.8.4. + Diag(MacroNameTok, diag::err_defined_macro_name); + } else if (isDefineUndef && II->hasMacroDefinition() && + getMacroInfo(II)->isBuiltinMacro()) { + // Error if defining "__LINE__" and other builtins: C99 6.10.8.4. + if (isDefineUndef == 1) + Diag(MacroNameTok, diag::pp_redef_builtin_macro); + else + Diag(MacroNameTok, diag::pp_undef_builtin_macro); + } else { + // Okay, we got a good identifier node. Return it. + return; + } + + // Invalid macro name, read and discard the rest of the line. Then set the + // token kind to tok::eom. + MacroNameTok.setKind(tok::eom); + return DiscardUntilEndOfDirective(); +} + +/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If +/// not, emit a diagnostic and consume up until the eom. +void Preprocessor::CheckEndOfDirective(const char *DirType) { + Token Tmp; + // Lex unexpanded tokens: macros might expand to zero tokens, causing us to + // miss diagnosing invalid lines. + LexUnexpandedToken(Tmp); + + // There should be no tokens after the directive, but we allow them as an + // extension. + while (Tmp.is(tok::comment)) // Skip comments in -C mode. + LexUnexpandedToken(Tmp); + + if (Tmp.isNot(tok::eom)) { + Diag(Tmp, diag::ext_pp_extra_tokens_at_eol, DirType); + DiscardUntilEndOfDirective(); + } +} + + + +/// SkipExcludedConditionalBlock - We just read a #if or related directive and +/// decided that the subsequent tokens are in the #if'd out portion of the +/// file. Lex the rest of the file, until we see an #endif. If +/// FoundNonSkipPortion is true, then we have already emitted code for part of +/// this #if directive, so #else/#elif blocks should never be entered. If ElseOk +/// is true, then #else directives are ok, if not, then we have already seen one +/// so a #else directive is a duplicate. When this returns, the caller can lex +/// the first valid token. +void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, + bool FoundElse) { + ++NumSkipped; + assert(CurTokenLexer == 0 && CurLexer && + "Lexing a macro, not a file?"); + + CurLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false, + FoundNonSkipPortion, FoundElse); + + // Enter raw mode to disable identifier lookup (and thus macro expansion), + // disabling warnings, etc. + CurLexer->LexingRawMode = true; + Token Tok; + while (1) { + CurLexer->Lex(Tok); + + // If this is the end of the buffer, we have an error. + if (Tok.is(tok::eof)) { + // Emit errors for each unterminated conditional on the stack, including + // the current one. + while (!CurLexer->ConditionalStack.empty()) { + Diag(CurLexer->ConditionalStack.back().IfLoc, + diag::err_pp_unterminated_conditional); + CurLexer->ConditionalStack.pop_back(); + } + + // Just return and let the caller lex after this #include. + break; + } + + // If this token is not a preprocessor directive, just skip it. + if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine()) + continue; + + // We just parsed a # character at the start of a line, so we're in + // directive mode. Tell the lexer this so any newlines we see will be + // converted into an EOM token (this terminates the macro). + CurLexer->ParsingPreprocessorDirective = true; + CurLexer->KeepCommentMode = false; + + + // Read the next token, the directive flavor. + LexUnexpandedToken(Tok); + + // If this isn't an identifier directive (e.g. is "# 1\n" or "#\n", or + // something bogus), skip it. + if (Tok.isNot(tok::identifier)) { + CurLexer->ParsingPreprocessorDirective = false; + // Restore comment saving mode. + CurLexer->KeepCommentMode = KeepComments; + continue; + } + + // If the first letter isn't i or e, it isn't intesting to us. We know that + // this is safe in the face of spelling differences, because there is no way + // to spell an i/e in a strange way that is another letter. Skipping this + // allows us to avoid looking up the identifier info for #define/#undef and + // other common directives. + const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation()); + char FirstChar = RawCharData[0]; + if (FirstChar >= 'a' && FirstChar <= 'z' && + FirstChar != 'i' && FirstChar != 'e') { + CurLexer->ParsingPreprocessorDirective = false; + // Restore comment saving mode. + CurLexer->KeepCommentMode = KeepComments; + continue; + } + + // Get the identifier name without trigraphs or embedded newlines. Note + // that we can't use Tok.getIdentifierInfo() because its lookup is disabled + // when skipping. + // TODO: could do this with zero copies in the no-clean case by using + // strncmp below. + char Directive[20]; + unsigned IdLen; + if (!Tok.needsCleaning() && Tok.getLength() < 20) { + IdLen = Tok.getLength(); + memcpy(Directive, RawCharData, IdLen); + Directive[IdLen] = 0; + } else { + std::string DirectiveStr = getSpelling(Tok); + IdLen = DirectiveStr.size(); + if (IdLen >= 20) { + CurLexer->ParsingPreprocessorDirective = false; + // Restore comment saving mode. + CurLexer->KeepCommentMode = KeepComments; + continue; + } + memcpy(Directive, &DirectiveStr[0], IdLen); + Directive[IdLen] = 0; + } + + if (FirstChar == 'i' && Directive[1] == 'f') { + if ((IdLen == 2) || // "if" + (IdLen == 5 && !strcmp(Directive+2, "def")) || // "ifdef" + (IdLen == 6 && !strcmp(Directive+2, "ndef"))) { // "ifndef" + // We know the entire #if/#ifdef/#ifndef block will be skipped, don't + // bother parsing the condition. + DiscardUntilEndOfDirective(); + CurLexer->pushConditionalLevel(Tok.getLocation(), /*wasskipping*/true, + /*foundnonskip*/false, + /*fnddelse*/false); + } + } else if (FirstChar == 'e') { + if (IdLen == 5 && !strcmp(Directive+1, "ndif")) { // "endif" + CheckEndOfDirective("#endif"); + PPConditionalInfo CondInfo; + CondInfo.WasSkipping = true; // Silence bogus warning. + bool InCond = CurLexer->popConditionalLevel(CondInfo); + InCond = InCond; // Silence warning in no-asserts mode. + assert(!InCond && "Can't be skipping if not in a conditional!"); + + // If we popped the outermost skipping block, we're done skipping! + if (!CondInfo.WasSkipping) + break; + } else if (IdLen == 4 && !strcmp(Directive+1, "lse")) { // "else". + // #else directive in a skipping conditional. If not in some other + // skipping conditional, and if #else hasn't already been seen, enter it + // as a non-skipping conditional. + CheckEndOfDirective("#else"); + PPConditionalInfo &CondInfo = CurLexer->peekConditionalLevel(); + + // If this is a #else with a #else before it, report the error. + if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_else_after_else); + + // Note that we've seen a #else in this conditional. + CondInfo.FoundElse = true; + + // If the conditional is at the top level, and the #if block wasn't + // entered, enter the #else block now. + if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) { + CondInfo.FoundNonSkip = true; + break; + } + } else if (IdLen == 4 && !strcmp(Directive+1, "lif")) { // "elif". + PPConditionalInfo &CondInfo = CurLexer->peekConditionalLevel(); + + bool ShouldEnter; + // If this is in a skipping block or if we're already handled this #if + // block, don't bother parsing the condition. + if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) { + DiscardUntilEndOfDirective(); + ShouldEnter = false; + } else { + // Restore the value of LexingRawMode so that identifiers are + // looked up, etc, inside the #elif expression. + assert(CurLexer->LexingRawMode && "We have to be skipping here!"); + CurLexer->LexingRawMode = false; + IdentifierInfo *IfNDefMacro = 0; + ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro); + CurLexer->LexingRawMode = true; + } + + // If this is a #elif with a #else before it, report the error. + if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else); + + // If this condition is true, enter it! + if (ShouldEnter) { + CondInfo.FoundNonSkip = true; + break; + } + } + } + + CurLexer->ParsingPreprocessorDirective = false; + // Restore comment saving mode. + CurLexer->KeepCommentMode = KeepComments; + } + + // Finally, if we are out of the conditional (saw an #endif or ran off the end + // of the file, just stop skipping and return to lexing whatever came after + // the #if block. + CurLexer->LexingRawMode = false; +} + +/// LookupFile - Given a "foo" or reference, look up the indicated file, +/// return null on failure. isAngled indicates whether the file reference is +/// for system #include's or not (i.e. using <> instead of ""). +const FileEntry *Preprocessor::LookupFile(const char *FilenameStart, + const char *FilenameEnd, + bool isAngled, + const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir) { + // If the header lookup mechanism may be relative to the current file, pass in + // info about where the current file is. + const FileEntry *CurFileEnt = 0; + if (!FromDir) { + SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc(); + CurFileEnt = SourceMgr.getFileEntryForLoc(FileLoc); + } + + // Do a standard file entry lookup. + CurDir = CurDirLookup; + const FileEntry *FE = + HeaderInfo.LookupFile(FilenameStart, FilenameEnd, + isAngled, FromDir, CurDir, CurFileEnt); + if (FE) return FE; + + // Otherwise, see if this is a subframework header. If so, this is relative + // to one of the headers on the #include stack. Walk the list of the current + // headers on the #include stack and pass them to HeaderInfo. + if (CurLexer && !CurLexer->Is_PragmaLexer) { + if ((CurFileEnt = SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc()))) + if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, FilenameEnd, + CurFileEnt))) + return FE; + } + + for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) { + IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1]; + if (ISEntry.TheLexer && !ISEntry.TheLexer->Is_PragmaLexer) { + if ((CurFileEnt = + SourceMgr.getFileEntryForLoc(ISEntry.TheLexer->getFileLoc()))) + if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, + FilenameEnd, CurFileEnt))) + return FE; + } + } + + // Otherwise, we really couldn't find the file. + return 0; +} + + +//===----------------------------------------------------------------------===// +// Preprocessor Directive Handling. +//===----------------------------------------------------------------------===// + +/// HandleDirective - This callback is invoked when the lexer sees a # token +/// at the start of a line. This consumes the directive, modifies the +/// lexer/preprocessor state, and advances the lexer(s) so that the next token +/// read is the correct one. +void Preprocessor::HandleDirective(Token &Result) { + // FIXME: Traditional: # with whitespace before it not recognized by K&R? + + // We just parsed a # character at the start of a line, so we're in directive + // mode. Tell the lexer this so any newlines we see will be converted into an + // EOM token (which terminates the directive). + CurLexer->ParsingPreprocessorDirective = true; + + ++NumDirectives; + + // We are about to read a token. For the multiple-include optimization FA to + // work, we have to remember if we had read any tokens *before* this + // pp-directive. + bool ReadAnyTokensBeforeDirective = CurLexer->MIOpt.getHasReadAnyTokensVal(); + + // Read the next token, the directive flavor. This isn't expanded due to + // C99 6.10.3p8. + LexUnexpandedToken(Result); + + // C99 6.10.3p11: Is this preprocessor directive in macro invocation? e.g.: + // #define A(x) #x + // A(abc + // #warning blah + // def) + // If so, the user is relying on non-portable behavior, emit a diagnostic. + if (InMacroArgs) + Diag(Result, diag::ext_embedded_directive); + +TryAgain: + switch (Result.getKind()) { + case tok::eom: + return; // null directive. + case tok::comment: + // Handle stuff like "# /*foo*/ define X" in -E -C mode. + LexUnexpandedToken(Result); + goto TryAgain; + + case tok::numeric_constant: + // FIXME: implement # 7 line numbers! + DiscardUntilEndOfDirective(); + return; + default: + IdentifierInfo *II = Result.getIdentifierInfo(); + if (II == 0) break; // Not an identifier. + + // Ask what the preprocessor keyword ID is. + switch (II->getPPKeywordID()) { + default: break; + // C99 6.10.1 - Conditional Inclusion. + case tok::pp_if: + return HandleIfDirective(Result, ReadAnyTokensBeforeDirective); + case tok::pp_ifdef: + return HandleIfdefDirective(Result, false, true/*not valid for miopt*/); + case tok::pp_ifndef: + return HandleIfdefDirective(Result, true, ReadAnyTokensBeforeDirective); + case tok::pp_elif: + return HandleElifDirective(Result); + case tok::pp_else: + return HandleElseDirective(Result); + case tok::pp_endif: + return HandleEndifDirective(Result); + + // C99 6.10.2 - Source File Inclusion. + case tok::pp_include: + return HandleIncludeDirective(Result); // Handle #include. + + // C99 6.10.3 - Macro Replacement. + case tok::pp_define: + return HandleDefineDirective(Result); + case tok::pp_undef: + return HandleUndefDirective(Result); + + // C99 6.10.4 - Line Control. + case tok::pp_line: + // FIXME: implement #line + DiscardUntilEndOfDirective(); + return; + + // C99 6.10.5 - Error Directive. + case tok::pp_error: + return HandleUserDiagnosticDirective(Result, false); + + // C99 6.10.6 - Pragma Directive. + case tok::pp_pragma: + return HandlePragmaDirective(); + + // GNU Extensions. + case tok::pp_import: + return HandleImportDirective(Result); + case tok::pp_include_next: + return HandleIncludeNextDirective(Result); + + case tok::pp_warning: + Diag(Result, diag::ext_pp_warning_directive); + return HandleUserDiagnosticDirective(Result, true); + case tok::pp_ident: + return HandleIdentSCCSDirective(Result); + case tok::pp_sccs: + return HandleIdentSCCSDirective(Result); + case tok::pp_assert: + //isExtension = true; // FIXME: implement #assert + break; + case tok::pp_unassert: + //isExtension = true; // FIXME: implement #unassert + break; + } + break; + } + + // If we reached here, the preprocessing token is not valid! + Diag(Result, diag::err_pp_invalid_directive); + + // Read the rest of the PP line. + DiscardUntilEndOfDirective(); + + // Okay, we're done parsing the directive. +} + +void Preprocessor::HandleUserDiagnosticDirective(Token &Tok, + bool isWarning) { + // Read the rest of the line raw. We do this because we don't want macros + // to be expanded and we don't require that the tokens be valid preprocessing + // tokens. For example, this is allowed: "#warning ` 'foo". GCC does + // collapse multiple consequtive white space between tokens, but this isn't + // specified by the standard. + std::string Message = CurLexer->ReadToEndOfLine(); + + unsigned DiagID = isWarning ? diag::pp_hash_warning : diag::err_pp_hash_error; + return Diag(Tok, DiagID, Message); +} + +/// HandleIdentSCCSDirective - Handle a #ident/#sccs directive. +/// +void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { + // Yes, this directive is an extension. + Diag(Tok, diag::ext_pp_ident_directive); + + // Read the string argument. + Token StrTok; + Lex(StrTok); + + // If the token kind isn't a string, it's a malformed directive. + if (StrTok.isNot(tok::string_literal) && + StrTok.isNot(tok::wide_string_literal)) + return Diag(StrTok, diag::err_pp_malformed_ident); + + // Verify that there is nothing after the string, other than EOM. + CheckEndOfDirective("#ident"); + + if (Callbacks) + Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok)); +} + +//===----------------------------------------------------------------------===// +// Preprocessor Include Directive Handling. +//===----------------------------------------------------------------------===// + +/// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully +/// checked and spelled filename, e.g. as an operand of #include. This returns +/// true if the input filename was in <>'s or false if it were in ""'s. The +/// caller is expected to provide a buffer that is large enough to hold the +/// spelling of the filename, but is also expected to handle the case when +/// this method decides to use a different buffer. +bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, + const char *&BufStart, + const char *&BufEnd) { + // Get the text form of the filename. + assert(BufStart != BufEnd && "Can't have tokens with empty spellings!"); + + // Make sure the filename is or "x". + bool isAngled; + if (BufStart[0] == '<') { + if (BufEnd[-1] != '>') { + Diag(Loc, diag::err_pp_expects_filename); + BufStart = 0; + return true; + } + isAngled = true; + } else if (BufStart[0] == '"') { + if (BufEnd[-1] != '"') { + Diag(Loc, diag::err_pp_expects_filename); + BufStart = 0; + return true; + } + isAngled = false; + } else { + Diag(Loc, diag::err_pp_expects_filename); + BufStart = 0; + return true; + } + + // Diagnose #include "" as invalid. + if (BufEnd-BufStart <= 2) { + Diag(Loc, diag::err_pp_empty_filename); + BufStart = 0; + return ""; + } + + // Skip the brackets. + ++BufStart; + --BufEnd; + return isAngled; +} + +/// ConcatenateIncludeName - Handle cases where the #include name is expanded +/// from a macro as multiple tokens, which need to be glued together. This +/// occurs for code like: +/// #define FOO +/// #include FOO +/// because in this case, "" is returned as 7 tokens, not one. +/// +/// This code concatenates and consumes tokens up to the '>' token. It returns +/// false if the > was found, otherwise it returns true if it finds and consumes +/// the EOM marker. +static bool ConcatenateIncludeName(llvm::SmallVector &FilenameBuffer, + Preprocessor &PP) { + Token CurTok; + + PP.Lex(CurTok); + while (CurTok.isNot(tok::eom)) { + // Append the spelling of this token to the buffer. If there was a space + // before it, add it now. + if (CurTok.hasLeadingSpace()) + FilenameBuffer.push_back(' '); + + // Get the spelling of the token, directly into FilenameBuffer if possible. + unsigned PreAppendSize = FilenameBuffer.size(); + FilenameBuffer.resize(PreAppendSize+CurTok.getLength()); + + const char *BufPtr = &FilenameBuffer[PreAppendSize]; + unsigned ActualLen = PP.getSpelling(CurTok, BufPtr); + + // If the token was spelled somewhere else, copy it into FilenameBuffer. + if (BufPtr != &FilenameBuffer[PreAppendSize]) + memcpy(&FilenameBuffer[PreAppendSize], BufPtr, ActualLen); + + // Resize FilenameBuffer to the correct size. + if (CurTok.getLength() != ActualLen) + FilenameBuffer.resize(PreAppendSize+ActualLen); + + // If we found the '>' marker, return success. + if (CurTok.is(tok::greater)) + return false; + + PP.Lex(CurTok); + } + + // If we hit the eom marker, emit an error and return true so that the caller + // knows the EOM has been read. + PP.Diag(CurTok.getLocation(), diag::err_pp_expects_filename); + return true; +} + +/// HandleIncludeDirective - The "#include" tokens have just been read, read the +/// file to be included from the lexer, then include it! This is a common +/// routine with functionality shared between #include, #include_next and +/// #import. +void Preprocessor::HandleIncludeDirective(Token &IncludeTok, + const DirectoryLookup *LookupFrom, + bool isImport) { + + Token FilenameTok; + CurLexer->LexIncludeFilename(FilenameTok); + + // Reserve a buffer to get the spelling. + llvm::SmallVector FilenameBuffer; + const char *FilenameStart, *FilenameEnd; + + switch (FilenameTok.getKind()) { + case tok::eom: + // If the token kind is EOM, the error has already been diagnosed. + return; + + case tok::angle_string_literal: + case tok::string_literal: { + FilenameBuffer.resize(FilenameTok.getLength()); + FilenameStart = &FilenameBuffer[0]; + unsigned Len = getSpelling(FilenameTok, FilenameStart); + FilenameEnd = FilenameStart+Len; + break; + } + + case tok::less: + // This could be a file coming from a macro expansion. In this + // case, glue the tokens together into FilenameBuffer and interpret those. + FilenameBuffer.push_back('<'); + if (ConcatenateIncludeName(FilenameBuffer, *this)) + return; // Found but no ">"? Diagnostic already emitted. + FilenameStart = &FilenameBuffer[0]; + FilenameEnd = &FilenameBuffer[FilenameBuffer.size()]; + break; + default: + Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); + DiscardUntilEndOfDirective(); + return; + } + + bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), + FilenameStart, FilenameEnd); + // If GetIncludeFilenameSpelling set the start ptr to null, there was an + // error. + if (FilenameStart == 0) { + DiscardUntilEndOfDirective(); + return; + } + + // Verify that there is nothing after the filename, other than EOM. Use the + // preprocessor to lex this in case lexing the filename entered a macro. + CheckEndOfDirective("#include"); + + // Check that we don't have infinite #include recursion. + if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) + return Diag(FilenameTok, diag::err_pp_include_too_deep); + + // Search include directories. + const DirectoryLookup *CurDir; + const FileEntry *File = LookupFile(FilenameStart, FilenameEnd, + isAngled, LookupFrom, CurDir); + if (File == 0) + return Diag(FilenameTok, diag::err_pp_file_not_found, + std::string(FilenameStart, FilenameEnd)); + + // Ask HeaderInfo if we should enter this #include file. + if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) { + // If it returns true, #including this file will have no effect. + return; + } + + // Look up the file, create a File ID for it. + unsigned FileID = SourceMgr.createFileID(File, FilenameTok.getLocation()); + if (FileID == 0) + return Diag(FilenameTok, diag::err_pp_file_not_found, + std::string(FilenameStart, FilenameEnd)); + + // Finally, if all is good, enter the new file! + EnterSourceFile(FileID, CurDir); +} + +/// HandleIncludeNextDirective - Implements #include_next. +/// +void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) { + Diag(IncludeNextTok, diag::ext_pp_include_next_directive); + + // #include_next is like #include, except that we start searching after + // the current found directory. If we can't do this, issue a + // diagnostic. + const DirectoryLookup *Lookup = CurDirLookup; + if (isInPrimaryFile()) { + Lookup = 0; + Diag(IncludeNextTok, diag::pp_include_next_in_primary); + } else if (Lookup == 0) { + Diag(IncludeNextTok, diag::pp_include_next_absolute_path); + } else { + // Start looking up in the next directory. + ++Lookup; + } + + return HandleIncludeDirective(IncludeNextTok, Lookup); +} + +/// HandleImportDirective - Implements #import. +/// +void Preprocessor::HandleImportDirective(Token &ImportTok) { + Diag(ImportTok, diag::ext_pp_import_directive); + + return HandleIncludeDirective(ImportTok, 0, true); +} + +//===----------------------------------------------------------------------===// +// Preprocessor Macro Directive Handling. +//===----------------------------------------------------------------------===// + +/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro +/// definition has just been read. Lex the rest of the arguments and the +/// closing ), updating MI with what we learn. Return true if an error occurs +/// parsing the arg list. +bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) { + llvm::SmallVector Arguments; + + Token Tok; + while (1) { + LexUnexpandedToken(Tok); + switch (Tok.getKind()) { + case tok::r_paren: + // Found the end of the argument list. + if (Arguments.empty()) { // #define FOO() + MI->setArgumentList(Arguments.begin(), Arguments.end()); + return false; + } + // Otherwise we have #define FOO(A,) + Diag(Tok, diag::err_pp_expected_ident_in_arg_list); + return true; + case tok::ellipsis: // #define X(... -> C99 varargs + // Warn if use of C99 feature in non-C99 mode. + if (!Features.C99) Diag(Tok, diag::ext_variadic_macro); + + // Lex the token after the identifier. + LexUnexpandedToken(Tok); + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); + return true; + } + // Add the __VA_ARGS__ identifier as an argument. + Arguments.push_back(Ident__VA_ARGS__); + MI->setIsC99Varargs(); + MI->setArgumentList(Arguments.begin(), Arguments.end()); + return false; + case tok::eom: // #define X( + Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); + return true; + default: + // Handle keywords and identifiers here to accept things like + // #define Foo(for) for. + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II == 0) { + // #define X(1 + Diag(Tok, diag::err_pp_invalid_tok_in_arg_list); + return true; + } + + // If this is already used as an argument, it is used multiple times (e.g. + // #define X(A,A. + if (std::find(Arguments.begin(), Arguments.end(), II) != + Arguments.end()) { // C99 6.10.3p6 + Diag(Tok, diag::err_pp_duplicate_name_in_arg_list, II->getName()); + return true; + } + + // Add the argument to the macro info. + Arguments.push_back(II); + + // Lex the token after the identifier. + LexUnexpandedToken(Tok); + + switch (Tok.getKind()) { + default: // #define X(A B + Diag(Tok, diag::err_pp_expected_comma_in_arg_list); + return true; + case tok::r_paren: // #define X(A) + MI->setArgumentList(Arguments.begin(), Arguments.end()); + return false; + case tok::comma: // #define X(A, + break; + case tok::ellipsis: // #define X(A... -> GCC extension + // Diagnose extension. + Diag(Tok, diag::ext_named_variadic_macro); + + // Lex the token after the identifier. + LexUnexpandedToken(Tok); + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); + return true; + } + + MI->setIsGNUVarargs(); + MI->setArgumentList(Arguments.begin(), Arguments.end()); + return false; + } + } + } +} + +/// HandleDefineDirective - Implements #define. This consumes the entire macro +/// line then lets the caller lex the next real token. +void Preprocessor::HandleDefineDirective(Token &DefineTok) { + ++NumDefined; + + Token MacroNameTok; + ReadMacroName(MacroNameTok, 1); + + // Error reading macro name? If so, diagnostic already issued. + if (MacroNameTok.is(tok::eom)) + return; + + // If we are supposed to keep comments in #defines, reenable comment saving + // mode. + CurLexer->KeepCommentMode = KeepMacroComments; + + // Create the new macro. + MacroInfo *MI = new MacroInfo(MacroNameTok.getLocation()); + + Token Tok; + LexUnexpandedToken(Tok); + + // If this is a function-like macro definition, parse the argument list, + // marking each of the identifiers as being used as macro arguments. Also, + // check other constraints on the first token of the macro body. + if (Tok.is(tok::eom)) { + // If there is no body to this macro, we have no special handling here. + } else if (Tok.is(tok::l_paren) && !Tok.hasLeadingSpace()) { + // This is a function-like macro definition. Read the argument list. + MI->setIsFunctionLike(); + if (ReadMacroDefinitionArgList(MI)) { + // Forget about MI. + delete MI; + // Throw away the rest of the line. + if (CurLexer->ParsingPreprocessorDirective) + DiscardUntilEndOfDirective(); + return; + } + + // Read the first token after the arg list for down below. + LexUnexpandedToken(Tok); + } else if (!Tok.hasLeadingSpace()) { + // C99 requires whitespace between the macro definition and the body. Emit + // a diagnostic for something like "#define X+". + if (Features.C99) { + Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name); + } else { + // FIXME: C90/C++ do not get this diagnostic, but it does get a similar + // one in some cases! + } + } else { + // This is a normal token with leading space. Clear the leading space + // marker on the first token to get proper expansion. + Tok.clearFlag(Token::LeadingSpace); + } + + // If this is a definition of a variadic C99 function-like macro, not using + // the GNU named varargs extension, enabled __VA_ARGS__. + + // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. + // This gets unpoisoned where it is allowed. + assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned!"); + if (MI->isC99Varargs()) + Ident__VA_ARGS__->setIsPoisoned(false); + + // Read the rest of the macro body. + if (MI->isObjectLike()) { + // Object-like macros are very simple, just read their body. + while (Tok.isNot(tok::eom)) { + MI->AddTokenToBody(Tok); + // Get the next token of the macro. + LexUnexpandedToken(Tok); + } + + } else { + // Otherwise, read the body of a function-like macro. This has to validate + // the # (stringize) operator. + while (Tok.isNot(tok::eom)) { + MI->AddTokenToBody(Tok); + + // Check C99 6.10.3.2p1: ensure that # operators are followed by macro + // parameters in function-like macro expansions. + if (Tok.isNot(tok::hash)) { + // Get the next token of the macro. + LexUnexpandedToken(Tok); + continue; + } + + // Get the next token of the macro. + LexUnexpandedToken(Tok); + + // Not a macro arg identifier? + if (!Tok.getIdentifierInfo() || + MI->getArgumentNum(Tok.getIdentifierInfo()) == -1) { + Diag(Tok, diag::err_pp_stringize_not_parameter); + delete MI; + + // Disable __VA_ARGS__ again. + Ident__VA_ARGS__->setIsPoisoned(true); + return; + } + + // Things look ok, add the param name token to the macro. + MI->AddTokenToBody(Tok); + + // Get the next token of the macro. + LexUnexpandedToken(Tok); + } + } + + + // Disable __VA_ARGS__ again. + Ident__VA_ARGS__->setIsPoisoned(true); + + // Check that there is no paste (##) operator at the begining or end of the + // replacement list. + unsigned NumTokens = MI->getNumTokens(); + if (NumTokens != 0) { + if (MI->getReplacementToken(0).is(tok::hashhash)) { + Diag(MI->getReplacementToken(0), diag::err_paste_at_start); + delete MI; + return; + } + if (MI->getReplacementToken(NumTokens-1).is(tok::hashhash)) { + Diag(MI->getReplacementToken(NumTokens-1), diag::err_paste_at_end); + delete MI; + return; + } + } + + // If this is the primary source file, remember that this macro hasn't been + // used yet. + if (isInPrimaryFile()) + MI->setIsUsed(false); + + // Finally, if this identifier already had a macro defined for it, verify that + // the macro bodies are identical and free the old definition. + if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) { + if (!OtherMI->isUsed()) + Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used); + + // Macros must be identical. This means all tokes and whitespace separation + // must be the same. C99 6.10.3.2. + if (!MI->isIdenticalTo(*OtherMI, *this)) { + Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef, + MacroNameTok.getIdentifierInfo()->getName()); + Diag(OtherMI->getDefinitionLoc(), diag::ext_pp_macro_redef2); + } + delete OtherMI; + } + + setMacroInfo(MacroNameTok.getIdentifierInfo(), MI); +} + +/// HandleUndefDirective - Implements #undef. +/// +void Preprocessor::HandleUndefDirective(Token &UndefTok) { + ++NumUndefined; + + Token MacroNameTok; + ReadMacroName(MacroNameTok, 2); + + // Error reading macro name? If so, diagnostic already issued. + if (MacroNameTok.is(tok::eom)) + return; + + // Check to see if this is the last token on the #undef line. + CheckEndOfDirective("#undef"); + + // Okay, we finally have a valid identifier to undef. + MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo()); + + // If the macro is not defined, this is a noop undef, just return. + if (MI == 0) return; + + if (!MI->isUsed()) + Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used); + + // Free macro definition. + delete MI; + setMacroInfo(MacroNameTok.getIdentifierInfo(), 0); +} + + +//===----------------------------------------------------------------------===// +// Preprocessor Conditional Directive Handling. +//===----------------------------------------------------------------------===// + +/// HandleIfdefDirective - Implements the #ifdef/#ifndef directive. isIfndef is +/// true when this is a #ifndef directive. ReadAnyTokensBeforeDirective is true +/// if any tokens have been returned or pp-directives activated before this +/// #ifndef has been lexed. +/// +void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, + bool ReadAnyTokensBeforeDirective) { + ++NumIf; + Token DirectiveTok = Result; + + Token MacroNameTok; + ReadMacroName(MacroNameTok); + + // Error reading macro name? If so, diagnostic already issued. + if (MacroNameTok.is(tok::eom)) { + // Skip code until we get to #endif. This helps with recovery by not + // emitting an error when the #endif is reached. + SkipExcludedConditionalBlock(DirectiveTok.getLocation(), + /*Foundnonskip*/false, /*FoundElse*/false); + return; + } + + // Check to see if this is the last token on the #if[n]def line. + CheckEndOfDirective(isIfndef ? "#ifndef" : "#ifdef"); + + if (CurLexer->getConditionalStackDepth() == 0) { + // If the start of a top-level #ifdef, inform MIOpt. + if (!ReadAnyTokensBeforeDirective) { + assert(isIfndef && "#ifdef shouldn't reach here"); + CurLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo()); + } else + CurLexer->MIOpt.EnterTopLevelConditional(); + } + + IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); + MacroInfo *MI = getMacroInfo(MII); + + // If there is a macro, process it. + if (MI) // Mark it used. + MI->setIsUsed(true); + + // Should we include the stuff contained by this directive? + if (!MI == isIfndef) { + // Yes, remember that we are inside a conditional, then lex the next token. + CurLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false, + /*foundnonskip*/true, /*foundelse*/false); + } else { + // No, skip the contents of this block and return the first token after it. + SkipExcludedConditionalBlock(DirectiveTok.getLocation(), + /*Foundnonskip*/false, + /*FoundElse*/false); + } +} + +/// HandleIfDirective - Implements the #if directive. +/// +void Preprocessor::HandleIfDirective(Token &IfToken, + bool ReadAnyTokensBeforeDirective) { + ++NumIf; + + // Parse and evaluation the conditional expression. + IdentifierInfo *IfNDefMacro = 0; + bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro); + + // Should we include the stuff contained by this directive? + if (ConditionalTrue) { + // If this condition is equivalent to #ifndef X, and if this is the first + // directive seen, handle it for the multiple-include optimization. + if (CurLexer->getConditionalStackDepth() == 0) { + if (!ReadAnyTokensBeforeDirective && IfNDefMacro) + CurLexer->MIOpt.EnterTopLevelIFNDEF(IfNDefMacro); + else + CurLexer->MIOpt.EnterTopLevelConditional(); + } + + // Yes, remember that we are inside a conditional, then lex the next token. + CurLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false, + /*foundnonskip*/true, /*foundelse*/false); + } else { + // No, skip the contents of this block and return the first token after it. + SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false, + /*FoundElse*/false); + } +} + +/// HandleEndifDirective - Implements the #endif directive. +/// +void Preprocessor::HandleEndifDirective(Token &EndifToken) { + ++NumEndif; + + // Check that this is the whole directive. + CheckEndOfDirective("#endif"); + + PPConditionalInfo CondInfo; + if (CurLexer->popConditionalLevel(CondInfo)) { + // No conditionals on the stack: this is an #endif without an #if. + return Diag(EndifToken, diag::err_pp_endif_without_if); + } + + // If this the end of a top-level #endif, inform MIOpt. + if (CurLexer->getConditionalStackDepth() == 0) + CurLexer->MIOpt.ExitTopLevelConditional(); + + assert(!CondInfo.WasSkipping && !CurLexer->LexingRawMode && + "This code should only be reachable in the non-skipping case!"); +} + + +void Preprocessor::HandleElseDirective(Token &Result) { + ++NumElse; + + // #else directive in a non-skipping conditional... start skipping. + CheckEndOfDirective("#else"); + + PPConditionalInfo CI; + if (CurLexer->popConditionalLevel(CI)) + return Diag(Result, diag::pp_err_else_without_if); + + // If this is a top-level #else, inform the MIOpt. + if (CurLexer->getConditionalStackDepth() == 0) + CurLexer->MIOpt.EnterTopLevelConditional(); + + // If this is a #else with a #else before it, report the error. + if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else); + + // Finally, skip the rest of the contents of this block and return the first + // token after it. + return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, + /*FoundElse*/true); +} + +void Preprocessor::HandleElifDirective(Token &ElifToken) { + ++NumElse; + + // #elif directive in a non-skipping conditional... start skipping. + // We don't care what the condition is, because we will always skip it (since + // the block immediately before it was included). + DiscardUntilEndOfDirective(); + + PPConditionalInfo CI; + if (CurLexer->popConditionalLevel(CI)) + return Diag(ElifToken, diag::pp_err_elif_without_if); + + // If this is a top-level #elif, inform the MIOpt. + if (CurLexer->getConditionalStackDepth() == 0) + CurLexer->MIOpt.EnterTopLevelConditional(); + + // If this is a #elif with a #else before it, report the error. + if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else); + + // Finally, skip the rest of the contents of this block and return the first + // token after it. + return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, + /*FoundElse*/CI.FoundElse); +} + diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp new file mode 100644 index 00000000000..cca76289176 --- /dev/null +++ b/clang/lib/Lex/PPExpressions.cpp @@ -0,0 +1,639 @@ +//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Preprocessor::EvaluateDirectiveExpression method, +// which parses and evaluates integer constant expressions for #if directives. +// +//===----------------------------------------------------------------------===// +// +// FIXME: implement testing for #assert's. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec, + Token &PeekTok, bool ValueLive, + Preprocessor &PP); + +/// DefinedTracker - This struct is used while parsing expressions to keep track +/// of whether !defined(X) has been seen. +/// +/// With this simple scheme, we handle the basic forms: +/// !defined(X) and !defined X +/// but we also trivially handle (silly) stuff like: +/// !!!defined(X) and +!defined(X) and !+!+!defined(X) and !(defined(X)). +struct DefinedTracker { + /// Each time a Value is evaluated, it returns information about whether the + /// parsed value is of the form defined(X), !defined(X) or is something else. + enum TrackerState { + DefinedMacro, // defined(X) + NotDefinedMacro, // !defined(X) + Unknown // Something else. + } State; + /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this + /// indicates the macro that was checked. + IdentifierInfo *TheMacro; +}; + + + +/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and +/// return the computed value in Result. Return true if there was an error +/// parsing. This function also returns information about the form of the +/// expression in DT. See above for information on what DT means. +/// +/// If ValueLive is false, then this value is being evaluated in a context where +/// the result is not used. As such, avoid diagnostics that relate to +/// evaluation. +static bool EvaluateValue(llvm::APSInt &Result, Token &PeekTok, + DefinedTracker &DT, bool ValueLive, + Preprocessor &PP) { + Result = 0; + DT.State = DefinedTracker::Unknown; + + // If this token's spelling is a pp-identifier, check to see if it is + // 'defined' or if it is a macro. Note that we check here because many + // keywords are pp-identifiers, so we can't check the kind. + if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { + // If this identifier isn't 'defined' and it wasn't macro expanded, it turns + // into a simple 0, unless it is the C++ keyword "true", in which case it + // turns into "1". + if (II->getPPKeywordID() != tok::pp_defined) { + PP.Diag(PeekTok, diag::warn_pp_undef_identifier, II->getName()); + Result = II->getTokenID() == tok::kw_true; + Result.setIsUnsigned(false); // "0" is signed intmax_t 0. + PP.LexNonComment(PeekTok); + return false; + } + + // Handle "defined X" and "defined(X)". + + // Get the next token, don't expand it. + PP.LexUnexpandedToken(PeekTok); + + // Two options, it can either be a pp-identifier or a (. + bool InParens = false; + if (PeekTok.is(tok::l_paren)) { + // Found a paren, remember we saw it and skip it. + InParens = true; + PP.LexUnexpandedToken(PeekTok); + } + + // If we don't have a pp-identifier now, this is an error. + if ((II = PeekTok.getIdentifierInfo()) == 0) { + PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); + return true; + } + + // Otherwise, we got an identifier, is it defined to something? + Result = II->hasMacroDefinition(); + Result.setIsUnsigned(false); // Result is signed intmax_t. + + // If there is a macro, mark it used. + if (Result != 0 && ValueLive) { + MacroInfo *Macro = PP.getMacroInfo(II); + Macro->setIsUsed(true); + } + + // Consume identifier. + PP.LexNonComment(PeekTok); + + // If we are in parens, ensure we have a trailing ). + if (InParens) { + if (PeekTok.isNot(tok::r_paren)) { + PP.Diag(PeekTok, diag::err_pp_missing_rparen); + return true; + } + // Consume the ). + PP.LexNonComment(PeekTok); + } + + // Success, remember that we saw defined(X). + DT.State = DefinedTracker::DefinedMacro; + DT.TheMacro = II; + return false; + } + + switch (PeekTok.getKind()) { + default: // Non-value token. + PP.Diag(PeekTok, diag::err_pp_expr_bad_token); + return true; + case tok::eom: + case tok::r_paren: + // If there is no expression, report and exit. + PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr); + return true; + case tok::numeric_constant: { + llvm::SmallString<64> IntegerBuffer; + IntegerBuffer.resize(PeekTok.getLength()); + const char *ThisTokBegin = &IntegerBuffer[0]; + unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin); + NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + PeekTok.getLocation(), PP); + if (Literal.hadError) + return true; // a diagnostic was already reported. + + if (Literal.isFloatingLiteral() || Literal.isImaginary) { + PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal); + return true; + } + assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); + + // long long is a C99 feature. + if (!PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus0x + && Literal.isLongLong) + PP.Diag(PeekTok, diag::ext_longlong); + + // Parse the integer literal into Result. + if (Literal.GetIntegerValue(Result)) { + // Overflow parsing integer literal. + if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large); + Result.setIsUnsigned(true); + } else { + // Set the signedness of the result to match whether there was a U suffix + // or not. + Result.setIsUnsigned(Literal.isUnsigned); + + // Detect overflow based on whether the value is signed. If signed + // and if the value is too large, emit a warning "integer constant is so + // large that it is unsigned" e.g. on 12345678901234567890 where intmax_t + // is 64-bits. + if (!Literal.isUnsigned && Result.isNegative()) { + if (ValueLive)PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed); + Result.setIsUnsigned(true); + } + } + + // Consume the token. + PP.LexNonComment(PeekTok); + return false; + } + case tok::char_constant: { // 'x' + llvm::SmallString<32> CharBuffer; + CharBuffer.resize(PeekTok.getLength()); + const char *ThisTokBegin = &CharBuffer[0]; + unsigned ActualLength = PP.getSpelling(PeekTok, ThisTokBegin); + CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + PeekTok.getLocation(), PP); + if (Literal.hadError()) + return true; // A diagnostic was already emitted. + + // Character literals are always int or wchar_t, expand to intmax_t. + TargetInfo &TI = PP.getTargetInfo(); + unsigned NumBits = TI.getCharWidth(Literal.isWide()); + + // Set the width. + llvm::APSInt Val(NumBits); + // Set the value. + Val = Literal.getValue(); + // Set the signedness. + Val.setIsUnsigned(!TI.isCharSigned()); + + if (Result.getBitWidth() > Val.getBitWidth()) { + Result = Val.extend(Result.getBitWidth()); + } else { + assert(Result.getBitWidth() == Val.getBitWidth() && + "intmax_t smaller than char/wchar_t?"); + Result = Val; + } + + // Consume the token. + PP.LexNonComment(PeekTok); + return false; + } + case tok::l_paren: + PP.LexNonComment(PeekTok); // Eat the (. + // Parse the value and if there are any binary operators involved, parse + // them. + if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; + + // If this is a silly value like (X), which doesn't need parens, check for + // !(defined X). + if (PeekTok.is(tok::r_paren)) { + // Just use DT unmodified as our result. + } else { + if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP)) + return true; + + if (PeekTok.isNot(tok::r_paren)) { + PP.Diag(PeekTok, diag::err_pp_expected_rparen); + return true; + } + DT.State = DefinedTracker::Unknown; + } + PP.LexNonComment(PeekTok); // Eat the ). + return false; + + case tok::plus: + // Unary plus doesn't modify the value. + PP.LexNonComment(PeekTok); + return EvaluateValue(Result, PeekTok, DT, ValueLive, PP); + case tok::minus: { + SourceLocation Loc = PeekTok.getLocation(); + PP.LexNonComment(PeekTok); + if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; + // C99 6.5.3.3p3: The sign of the result matches the sign of the operand. + Result = -Result; + + bool Overflow = false; + if (Result.isUnsigned()) + Overflow = Result.isNegative(); + else if (Result.isMinSignedValue()) + Overflow = true; // -MININT is the only thing that overflows. + + // If this operator is live and overflowed, report the issue. + if (Overflow && ValueLive) + PP.Diag(Loc, diag::warn_pp_expr_overflow); + + DT.State = DefinedTracker::Unknown; + return false; + } + + case tok::tilde: + PP.LexNonComment(PeekTok); + if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; + // C99 6.5.3.3p4: The sign of the result matches the sign of the operand. + Result = ~Result; + DT.State = DefinedTracker::Unknown; + return false; + + case tok::exclaim: + PP.LexNonComment(PeekTok); + if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; + Result = !Result; + // C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed. + Result.setIsUnsigned(false); + + if (DT.State == DefinedTracker::DefinedMacro) + DT.State = DefinedTracker::NotDefinedMacro; + else if (DT.State == DefinedTracker::NotDefinedMacro) + DT.State = DefinedTracker::DefinedMacro; + return false; + + // FIXME: Handle #assert + } +} + + + +/// getPrecedence - Return the precedence of the specified binary operator +/// token. This returns: +/// ~0 - Invalid token. +/// 14 - *,/,% +/// 13 - -,+ +/// 12 - <<,>> +/// 11 - >=, <=, >, < +/// 10 - ==, != +/// 9 - & +/// 8 - ^ +/// 7 - | +/// 6 - && +/// 5 - || +/// 4 - ? +/// 3 - : +/// 0 - eom, ) +static unsigned getPrecedence(tok::TokenKind Kind) { + switch (Kind) { + default: return ~0U; + case tok::percent: + case tok::slash: + case tok::star: return 14; + case tok::plus: + case tok::minus: return 13; + case tok::lessless: + case tok::greatergreater: return 12; + case tok::lessequal: + case tok::less: + case tok::greaterequal: + case tok::greater: return 11; + case tok::exclaimequal: + case tok::equalequal: return 10; + case tok::amp: return 9; + case tok::caret: return 8; + case tok::pipe: return 7; + case tok::ampamp: return 6; + case tok::pipepipe: return 5; + case tok::question: return 4; + case tok::colon: return 3; + case tok::comma: return 2; + case tok::r_paren: return 0; // Lowest priority, end of expr. + case tok::eom: return 0; // Lowest priority, end of macro. + } +} + + +/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is +/// PeekTok, and whose precedence is PeekPrec. +/// +/// If ValueLive is false, then this value is being evaluated in a context where +/// the result is not used. As such, avoid diagnostics that relate to +/// evaluation. +static bool EvaluateDirectiveSubExpr(llvm::APSInt &LHS, unsigned MinPrec, + Token &PeekTok, bool ValueLive, + Preprocessor &PP) { + unsigned PeekPrec = getPrecedence(PeekTok.getKind()); + // If this token isn't valid, report the error. + if (PeekPrec == ~0U) { + PP.Diag(PeekTok, diag::err_pp_expr_bad_token); + return true; + } + + while (1) { + // If this token has a lower precedence than we are allowed to parse, return + // it so that higher levels of the recursion can parse it. + if (PeekPrec < MinPrec) + return false; + + tok::TokenKind Operator = PeekTok.getKind(); + + // If this is a short-circuiting operator, see if the RHS of the operator is + // dead. Note that this cannot just clobber ValueLive. Consider + // "0 && 1 ? 4 : 1 / 0", which is parsed as "(0 && 1) ? 4 : (1 / 0)". In + // this example, the RHS of the && being dead does not make the rest of the + // expr dead. + bool RHSIsLive; + if (Operator == tok::ampamp && LHS == 0) + RHSIsLive = false; // RHS of "0 && x" is dead. + else if (Operator == tok::pipepipe && LHS != 0) + RHSIsLive = false; // RHS of "1 || x" is dead. + else if (Operator == tok::question && LHS == 0) + RHSIsLive = false; // RHS (x) of "0 ? x : y" is dead. + else + RHSIsLive = ValueLive; + + // Consume the operator, saving the operator token for error reporting. + Token OpToken = PeekTok; + PP.LexNonComment(PeekTok); + + llvm::APSInt RHS(LHS.getBitWidth()); + // Parse the RHS of the operator. + DefinedTracker DT; + if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true; + + // Remember the precedence of this operator and get the precedence of the + // operator immediately to the right of the RHS. + unsigned ThisPrec = PeekPrec; + PeekPrec = getPrecedence(PeekTok.getKind()); + + // If this token isn't valid, report the error. + if (PeekPrec == ~0U) { + PP.Diag(PeekTok, diag::err_pp_expr_bad_token); + return true; + } + + bool isRightAssoc = Operator == tok::question; + + // Get the precedence of the operator to the right of the RHS. If it binds + // more tightly with RHS than we do, evaluate it completely first. + if (ThisPrec < PeekPrec || + (ThisPrec == PeekPrec && isRightAssoc)) { + if (EvaluateDirectiveSubExpr(RHS, ThisPrec+1, PeekTok, RHSIsLive, PP)) + return true; + PeekPrec = getPrecedence(PeekTok.getKind()); + } + assert(PeekPrec <= ThisPrec && "Recursion didn't work!"); + + // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if + // either operand is unsigned. Don't do this for x and y in "x ? y : z". + llvm::APSInt Res(LHS.getBitWidth()); + if (Operator != tok::question) { + Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned()); + // If this just promoted something from signed to unsigned, and if the + // value was negative, warn about it. + if (ValueLive && Res.isUnsigned()) { + if (!LHS.isUnsigned() && LHS.isNegative()) + PP.Diag(OpToken, diag::warn_pp_convert_lhs_to_positive, + LHS.toStringSigned() + " to " + LHS.toStringUnsigned()); + if (!RHS.isUnsigned() && RHS.isNegative()) + PP.Diag(OpToken, diag::warn_pp_convert_rhs_to_positive, + RHS.toStringSigned() + " to " + RHS.toStringUnsigned()); + } + LHS.setIsUnsigned(Res.isUnsigned()); + RHS.setIsUnsigned(Res.isUnsigned()); + } + + // FIXME: All of these should detect and report overflow?? + bool Overflow = false; + switch (Operator) { + default: assert(0 && "Unknown operator token!"); + case tok::percent: + if (RHS == 0) { + if (ValueLive) PP.Diag(OpToken, diag::err_pp_remainder_by_zero); + return true; + } + Res = LHS % RHS; + break; + case tok::slash: + if (RHS == 0) { + if (ValueLive) PP.Diag(OpToken, diag::err_pp_division_by_zero); + return true; + } + Res = LHS / RHS; + if (LHS.isSigned()) + Overflow = LHS.isMinSignedValue() && RHS.isAllOnesValue(); // MININT/-1 + break; + case tok::star: + Res = LHS * RHS; + if (LHS != 0 && RHS != 0) + Overflow = Res/RHS != LHS || Res/LHS != RHS; + break; + case tok::lessless: { + // Determine whether overflow is about to happen. + unsigned ShAmt = static_cast(RHS.getLimitedValue()); + if (ShAmt >= LHS.getBitWidth()) + Overflow = true, ShAmt = LHS.getBitWidth()-1; + else if (LHS.isUnsigned()) + Overflow = ShAmt > LHS.countLeadingZeros(); + else if (LHS.isNonNegative()) + Overflow = ShAmt >= LHS.countLeadingZeros(); // Don't allow sign change. + else + Overflow = ShAmt >= LHS.countLeadingOnes(); + + Res = LHS << ShAmt; + break; + } + case tok::greatergreater: { + // Determine whether overflow is about to happen. + unsigned ShAmt = static_cast(RHS.getLimitedValue()); + if (ShAmt >= LHS.getBitWidth()) + Overflow = true, ShAmt = LHS.getBitWidth()-1; + Res = LHS >> ShAmt; + break; + } + case tok::plus: + Res = LHS + RHS; + if (LHS.isUnsigned()) + Overflow = Res.ult(LHS); + else if (LHS.isNonNegative() == RHS.isNonNegative() && + Res.isNonNegative() != LHS.isNonNegative()) + Overflow = true; // Overflow for signed addition. + break; + case tok::minus: + Res = LHS - RHS; + if (LHS.isUnsigned()) + Overflow = Res.ugt(LHS); + else if (LHS.isNonNegative() != RHS.isNonNegative() && + Res.isNonNegative() != LHS.isNonNegative()) + Overflow = true; // Overflow for signed subtraction. + break; + case tok::lessequal: + Res = LHS <= RHS; + Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) + break; + case tok::less: + Res = LHS < RHS; + Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) + break; + case tok::greaterequal: + Res = LHS >= RHS; + Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) + break; + case tok::greater: + Res = LHS > RHS; + Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) + break; + case tok::exclaimequal: + Res = LHS != RHS; + Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed) + break; + case tok::equalequal: + Res = LHS == RHS; + Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed) + break; + case tok::amp: + Res = LHS & RHS; + break; + case tok::caret: + Res = LHS ^ RHS; + break; + case tok::pipe: + Res = LHS | RHS; + break; + case tok::ampamp: + Res = (LHS != 0 && RHS != 0); + Res.setIsUnsigned(false); // C99 6.5.13p3, result is always int (signed) + break; + case tok::pipepipe: + Res = (LHS != 0 || RHS != 0); + Res.setIsUnsigned(false); // C99 6.5.14p3, result is always int (signed) + break; + case tok::comma: + PP.Diag(OpToken, diag::ext_pp_comma_expr); + Res = RHS; // LHS = LHS,RHS -> RHS. + break; + case tok::question: { + // Parse the : part of the expression. + if (PeekTok.isNot(tok::colon)) { + PP.Diag(OpToken, diag::err_pp_question_without_colon); + return true; + } + // Consume the :. + PP.LexNonComment(PeekTok); + + // Evaluate the value after the :. + bool AfterColonLive = ValueLive && LHS == 0; + llvm::APSInt AfterColonVal(LHS.getBitWidth()); + DefinedTracker DT; + if (EvaluateValue(AfterColonVal, PeekTok, DT, AfterColonLive, PP)) + return true; + + // Parse anything after the : RHS that has a higher precedence than ?. + if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec+1, + PeekTok, AfterColonLive, PP)) + return true; + + // Now that we have the condition, the LHS and the RHS of the :, evaluate. + Res = LHS != 0 ? RHS : AfterColonVal; + + // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if + // either operand is unsigned. + Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned()); + + // Figure out the precedence of the token after the : part. + PeekPrec = getPrecedence(PeekTok.getKind()); + break; + } + case tok::colon: + // Don't allow :'s to float around without being part of ?: exprs. + PP.Diag(OpToken, diag::err_pp_colon_without_question); + return true; + } + + // If this operator is live and overflowed, report the issue. + if (Overflow && ValueLive) + PP.Diag(OpToken, diag::warn_pp_expr_overflow); + + // Put the result back into 'LHS' for our next iteration. + LHS = Res; + } + + return false; +} + +/// EvaluateDirectiveExpression - Evaluate an integer constant expression that +/// may occur after a #if or #elif directive. If the expression is equivalent +/// to "!defined(X)" return X in IfNDefMacro. +bool Preprocessor:: +EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { + // Peek ahead one token. + Token Tok; + Lex(Tok); + + // C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t. + unsigned BitWidth = getTargetInfo().getIntMaxTWidth(); + + llvm::APSInt ResVal(BitWidth); + DefinedTracker DT; + if (EvaluateValue(ResVal, Tok, DT, true, *this)) { + // Parse error, skip the rest of the macro line. + if (Tok.isNot(tok::eom)) + DiscardUntilEndOfDirective(); + return false; + } + + // If we are at the end of the expression after just parsing a value, there + // must be no (unparenthesized) binary operators involved, so we can exit + // directly. + if (Tok.is(tok::eom)) { + // If the expression we parsed was of the form !defined(macro), return the + // macro in IfNDefMacro. + if (DT.State == DefinedTracker::NotDefinedMacro) + IfNDefMacro = DT.TheMacro; + + return ResVal != 0; + } + + // Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the + // operator and the stuff after it. + if (EvaluateDirectiveSubExpr(ResVal, 1, Tok, true, *this)) { + // Parse error, skip the rest of the macro line. + if (Tok.isNot(tok::eom)) + DiscardUntilEndOfDirective(); + return false; + } + + // If we aren't at the tok::eom token, something bad happened, like an extra + // ')' token. + if (Tok.isNot(tok::eom)) { + Diag(Tok, diag::err_pp_expected_eol); + DiscardUntilEndOfDirective(); + } + + return ResVal != 0; +} + diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp new file mode 100644 index 00000000000..bd0ff7f94a1 --- /dev/null +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -0,0 +1,401 @@ +//===--- PPLexerChange.cpp - Handle changing lexers in the preprocessor ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements pieces of the Preprocessor interface that manage the +// current lexer stack. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +using namespace clang; + +PPCallbacks::~PPCallbacks() { +} + + +//===----------------------------------------------------------------------===// +// Miscellaneous Methods. +//===----------------------------------------------------------------------===// + +/// isInPrimaryFile - Return true if we're in the top-level file, not in a +/// #include. This looks through macro expansions and active _Pragma lexers. +bool Preprocessor::isInPrimaryFile() const { + if (CurLexer && !CurLexer->Is_PragmaLexer) + return IncludeMacroStack.empty(); + + // If there are any stacked lexers, we're in a #include. + assert(IncludeMacroStack[0].TheLexer && + !IncludeMacroStack[0].TheLexer->Is_PragmaLexer && + "Top level include stack isn't our primary lexer?"); + for (unsigned i = 1, e = IncludeMacroStack.size(); i != e; ++i) + if (IncludeMacroStack[i].TheLexer && + !IncludeMacroStack[i].TheLexer->Is_PragmaLexer) + return false; + return true; +} + +/// getCurrentLexer - Return the current file lexer being lexed from. Note +/// that this ignores any potentially active macro expansions and _Pragma +/// expansions going on at the time. +Lexer *Preprocessor::getCurrentFileLexer() const { + if (CurLexer && !CurLexer->Is_PragmaLexer) return CurLexer; + + // Look for a stacked lexer. + for (unsigned i = IncludeMacroStack.size(); i != 0; --i) { + Lexer *L = IncludeMacroStack[i-1].TheLexer; + if (L && !L->Is_PragmaLexer) // Ignore macro & _Pragma expansions. + return L; + } + return 0; +} + +/// LookAhead - This peeks ahead N tokens and returns that token without +/// consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) returns +/// the token after Tok, etc. +/// +/// NOTE: is a relatively expensive method, so it should not be used in common +/// code paths if possible! +/// +Token Preprocessor::LookAhead(unsigned N) { + // FIXME: Optimize the case where multiple lookahead calls are used back to + // back. Consider if the the parser contained (dynamically): + // Lookahead(1); Lookahead(1); Lookahead(1) + // This would return the same token 3 times, but would end up making lots of + // token stream lexers to do it. To handle this common case, see if the top + // of the lexer stack is a TokenStreamLexer with macro expansion disabled. If + // so, see if it has 'N' tokens available in it. If so, just return the + // token. + + // FIXME: Optimize the case when the parser does multiple nearby lookahead + // calls. For example, consider: + // Lookahead(0); Lookahead(1); Lookahead(2); + // The previous optimization won't apply, and there won't be any space left in + // the array that was previously new'd. To handle this, always round up the + // size we new to a multiple of 16 tokens. If the previous buffer has space + // left, we can just grow it. This means we only have to do the new 1/16th as + // often. + + Token *LookaheadTokens = new Token[N]; + + // Read N+1 tokens into LookaheadTokens. After this loop, Tok is the token + // to return. + Token Tok; + unsigned NumTokens = 0; + for (; N != ~0U; --N, ++NumTokens) { + Lex(Tok); + LookaheadTokens[NumTokens] = Tok; + + // If we got to EOF, don't lex past it. This will cause LookAhead to return + // the EOF token. + if (Tok.is(tok::eof)) + break; + } + + // Okay, at this point, we have the token we want to return in Tok. However, + // we read it and a bunch of other stuff (in LookaheadTokens) that we must + // allow subsequent calls to 'Lex' to return. To do this, we push a new token + // lexer onto the lexer stack with the tokens we read here. This passes + // ownership of LookaheadTokens to EnterTokenStream. + // + // Note that we disable macro expansion of the tokens from this buffer, since + // any macros have already been expanded, and the internal preprocessor state + // may already read past new macros. Consider something like LookAhead(1) on + // X + // #define X 14 + // Y + // The lookahead call should return 'Y', and the next Lex call should return + // 'X' even though X -> 14 has already been entered as a macro. + // + EnterTokenStream(LookaheadTokens, NumTokens, true /*DisableExpansion*/, + true /*OwnsTokens*/); + return Tok; +} + + +//===----------------------------------------------------------------------===// +// Methods for Entering and Callbacks for leaving various contexts +//===----------------------------------------------------------------------===// + +/// EnterSourceFile - Add a source file to the top of the include stack and +/// start lexing tokens from it instead of the current buffer. Return true +/// on failure. +void Preprocessor::EnterSourceFile(unsigned FileID, + const DirectoryLookup *CurDir) { + assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); + ++NumEnteredSourceFiles; + + if (MaxIncludeStackDepth < IncludeMacroStack.size()) + MaxIncludeStackDepth = IncludeMacroStack.size(); + + Lexer *TheLexer = new Lexer(SourceLocation::getFileLoc(FileID, 0), *this); + EnterSourceFileWithLexer(TheLexer, CurDir); +} + +/// EnterSourceFile - Add a source file to the top of the include stack and +/// start lexing tokens from it instead of the current buffer. +void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, + const DirectoryLookup *CurDir) { + + // Add the current lexer to the include stack. + if (CurLexer || CurTokenLexer) + IncludeMacroStack.push_back(IncludeStackInfo(CurLexer, CurDirLookup, + CurTokenLexer)); + + CurLexer = TheLexer; + CurDirLookup = CurDir; + CurTokenLexer = 0; + + // Notify the client, if desired, that we are in a new source file. + if (Callbacks && !CurLexer->Is_PragmaLexer) { + DirectoryLookup::DirType FileType = DirectoryLookup::NormalHeaderDir; + + // Get the file entry for the current file. + if (const FileEntry *FE = + SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc())) + FileType = HeaderInfo.getFileDirFlavor(FE); + + Callbacks->FileChanged(CurLexer->getFileLoc(), + PPCallbacks::EnterFile, FileType); + } +} + + + +/// EnterMacro - Add a Macro to the top of the include stack and start lexing +/// tokens from it instead of the current buffer. +void Preprocessor::EnterMacro(Token &Tok, MacroArgs *Args) { + IncludeMacroStack.push_back(IncludeStackInfo(CurLexer, CurDirLookup, + CurTokenLexer)); + CurLexer = 0; + CurDirLookup = 0; + + if (NumCachedTokenLexers == 0) { + CurTokenLexer = new TokenLexer(Tok, Args, *this); + } else { + CurTokenLexer = TokenLexerCache[--NumCachedTokenLexers]; + CurTokenLexer->Init(Tok, Args); + } +} + +/// EnterTokenStream - Add a "macro" context to the top of the include stack, +/// which will cause the lexer to start returning the specified tokens. +/// +/// If DisableMacroExpansion is true, tokens lexed from the token stream will +/// not be subject to further macro expansion. Otherwise, these tokens will +/// be re-macro-expanded when/if expansion is enabled. +/// +/// If OwnsTokens is false, this method assumes that the specified stream of +/// tokens has a permanent owner somewhere, so they do not need to be copied. +/// If it is true, it assumes the array of tokens is allocated with new[] and +/// must be freed. +/// +void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks, + bool DisableMacroExpansion, + bool OwnsTokens) { + // Save our current state. + IncludeMacroStack.push_back(IncludeStackInfo(CurLexer, CurDirLookup, + CurTokenLexer)); + CurLexer = 0; + CurDirLookup = 0; + + // Create a macro expander to expand from the specified token stream. + if (NumCachedTokenLexers == 0) { + CurTokenLexer = new TokenLexer(Toks, NumToks, DisableMacroExpansion, + OwnsTokens, *this); + } else { + CurTokenLexer = TokenLexerCache[--NumCachedTokenLexers]; + CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens); + } +} + +/// HandleEndOfFile - This callback is invoked when the lexer hits the end of +/// the current file. This either returns the EOF token or pops a level off +/// the include stack and keeps going. +bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { + assert(!CurTokenLexer && + "Ending a file when currently in a macro!"); + + // See if this file had a controlling macro. + if (CurLexer) { // Not ending a macro, ignore it. + if (const IdentifierInfo *ControllingMacro = + CurLexer->MIOpt.GetControllingMacroAtEndOfFile()) { + // Okay, this has a controlling macro, remember in PerFileInfo. + if (const FileEntry *FE = + SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc())) + HeaderInfo.SetFileControllingMacro(FE, ControllingMacro); + } + } + + // If this is a #include'd file, pop it off the include stack and continue + // lexing the #includer file. + if (!IncludeMacroStack.empty()) { + // We're done with the #included file. + RemoveTopOfLexerStack(); + + // Notify the client, if desired, that we are in a new source file. + if (Callbacks && !isEndOfMacro && CurLexer) { + DirectoryLookup::DirType FileType = DirectoryLookup::NormalHeaderDir; + + // Get the file entry for the current file. + if (const FileEntry *FE = + SourceMgr.getFileEntryForLoc(CurLexer->getFileLoc())) + FileType = HeaderInfo.getFileDirFlavor(FE); + + Callbacks->FileChanged(CurLexer->getSourceLocation(CurLexer->BufferPtr), + PPCallbacks::ExitFile, FileType); + } + + // Client should lex another token. + return false; + } + + // If the file ends with a newline, form the EOF token on the newline itself, + // rather than "on the line following it", which doesn't exist. This makes + // diagnostics relating to the end of file include the last file that the user + // actually typed, which is goodness. + const char *EndPos = CurLexer->BufferEnd; + if (EndPos != CurLexer->BufferStart && + (EndPos[-1] == '\n' || EndPos[-1] == '\r')) { + --EndPos; + + // Handle \n\r and \r\n: + if (EndPos != CurLexer->BufferStart && + (EndPos[-1] == '\n' || EndPos[-1] == '\r') && + EndPos[-1] != EndPos[0]) + --EndPos; + } + + Result.startToken(); + CurLexer->BufferPtr = EndPos; + CurLexer->FormTokenWithChars(Result, EndPos); + Result.setKind(tok::eof); + + // We're done with the #included file. + delete CurLexer; + CurLexer = 0; + + // This is the end of the top-level file. If the diag::pp_macro_not_used + // diagnostic is enabled, look for macros that have not been used. + if (Diags.getDiagnosticLevel(diag::pp_macro_not_used) != Diagnostic::Ignored){ + for (llvm::DenseMap::iterator I = + Macros.begin(), E = Macros.end(); I != E; ++I) { + if (!I->second->isUsed()) + Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used); + } + } + return true; +} + +/// HandleEndOfTokenLexer - This callback is invoked when the current TokenLexer +/// hits the end of its token stream. +bool Preprocessor::HandleEndOfTokenLexer(Token &Result) { + assert(CurTokenLexer && !CurLexer && + "Ending a macro when currently in a #include file!"); + + // Delete or cache the now-dead macro expander. + if (NumCachedTokenLexers == TokenLexerCacheSize) + delete CurTokenLexer; + else + TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer; + + // Handle this like a #include file being popped off the stack. + CurTokenLexer = 0; + return HandleEndOfFile(Result, true); +} + +/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the +/// lexer stack. This should only be used in situations where the current +/// state of the top-of-stack lexer is unknown. +void Preprocessor::RemoveTopOfLexerStack() { + assert(!IncludeMacroStack.empty() && "Ran out of stack entries to load"); + + if (CurTokenLexer) { + // Delete or cache the now-dead macro expander. + if (NumCachedTokenLexers == TokenLexerCacheSize) + delete CurTokenLexer; + else + TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer; + } else { + delete CurLexer; + } + CurLexer = IncludeMacroStack.back().TheLexer; + CurDirLookup = IncludeMacroStack.back().TheDirLookup; + CurTokenLexer = IncludeMacroStack.back().TheTokenLexer; + IncludeMacroStack.pop_back(); +} + +/// HandleMicrosoftCommentPaste - When the macro expander pastes together a +/// comment (/##/) in microsoft mode, this method handles updating the current +/// state, returning the token on the next source line. +void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { + assert(CurTokenLexer && !CurLexer && + "Pasted comment can only be formed from macro"); + + // We handle this by scanning for the closest real lexer, switching it to + // raw mode and preprocessor mode. This will cause it to return \n as an + // explicit EOM token. + Lexer *FoundLexer = 0; + bool LexerWasInPPMode = false; + for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) { + IncludeStackInfo &ISI = *(IncludeMacroStack.end()-i-1); + if (ISI.TheLexer == 0) continue; // Scan for a real lexer. + + // Once we find a real lexer, mark it as raw mode (disabling macro + // expansions) and preprocessor mode (return EOM). We know that the lexer + // was *not* in raw mode before, because the macro that the comment came + // from was expanded. However, it could have already been in preprocessor + // mode (#if COMMENT) in which case we have to return it to that mode and + // return EOM. + FoundLexer = ISI.TheLexer; + FoundLexer->LexingRawMode = true; + LexerWasInPPMode = FoundLexer->ParsingPreprocessorDirective; + FoundLexer->ParsingPreprocessorDirective = true; + break; + } + + // Okay, we either found and switched over the lexer, or we didn't find a + // lexer. In either case, finish off the macro the comment came from, getting + // the next token. + if (!HandleEndOfTokenLexer(Tok)) Lex(Tok); + + // Discarding comments as long as we don't have EOF or EOM. This 'comments + // out' the rest of the line, including any tokens that came from other macros + // that were active, as in: + // #define submacro a COMMENT b + // submacro c + // which should lex to 'a' only: 'b' and 'c' should be removed. + while (Tok.isNot(tok::eom) && Tok.isNot(tok::eof)) + Lex(Tok); + + // If we got an eom token, then we successfully found the end of the line. + if (Tok.is(tok::eom)) { + assert(FoundLexer && "Can't get end of line without an active lexer"); + // Restore the lexer back to normal mode instead of raw mode. + FoundLexer->LexingRawMode = false; + + // If the lexer was already in preprocessor mode, just return the EOM token + // to finish the preprocessor line. + if (LexerWasInPPMode) return; + + // Otherwise, switch out of PP mode and return the next lexed token. + FoundLexer->ParsingPreprocessorDirective = false; + return Lex(Tok); + } + + // If we got an EOF token, then we reached the end of the token stream but + // didn't find an explicit \n. This can only happen if there was no lexer + // active (an active lexer would return EOM at EOF if there was no \n in + // preprocessor directive mode), so just return EOF as our token. + assert(!FoundLexer && "Lexer should return EOM before EOF in PP mode"); +} diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp new file mode 100644 index 00000000000..8218d0ac06e --- /dev/null +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -0,0 +1,523 @@ +//===--- MacroExpansion.cpp - Top level Macro Expansion -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the top level handling of macro expasion for the +// preprocessor. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Preprocessor.h" +#include "MacroArgs.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/Diagnostic.h" +using namespace clang; + +/// setMacroInfo - Specify a macro for this identifier. +/// +void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) { + if (MI == 0) { + if (II->hasMacroDefinition()) { + Macros.erase(II); + II->setHasMacroDefinition(false); + } + } else { + Macros[II] = MI; + II->setHasMacroDefinition(true); + } +} + +/// RegisterBuiltinMacro - Register the specified identifier in the identifier +/// table and mark it as a builtin macro to be expanded. +IdentifierInfo *Preprocessor::RegisterBuiltinMacro(const char *Name) { + // Get the identifier. + IdentifierInfo *Id = getIdentifierInfo(Name); + + // Mark it as being a macro that is builtin. + MacroInfo *MI = new MacroInfo(SourceLocation()); + MI->setIsBuiltinMacro(); + setMacroInfo(Id, MI); + return Id; +} + + +/// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the +/// identifier table. +void Preprocessor::RegisterBuiltinMacros() { + Ident__LINE__ = RegisterBuiltinMacro("__LINE__"); + Ident__FILE__ = RegisterBuiltinMacro("__FILE__"); + Ident__DATE__ = RegisterBuiltinMacro("__DATE__"); + Ident__TIME__ = RegisterBuiltinMacro("__TIME__"); + Ident_Pragma = RegisterBuiltinMacro("_Pragma"); + + // GCC Extensions. + Ident__BASE_FILE__ = RegisterBuiltinMacro("__BASE_FILE__"); + Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro("__INCLUDE_LEVEL__"); + Ident__TIMESTAMP__ = RegisterBuiltinMacro("__TIMESTAMP__"); +} + +/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token +/// in its expansion, currently expands to that token literally. +static bool isTrivialSingleTokenExpansion(const MacroInfo *MI, + const IdentifierInfo *MacroIdent, + Preprocessor &PP) { + IdentifierInfo *II = MI->getReplacementToken(0).getIdentifierInfo(); + + // If the token isn't an identifier, it's always literally expanded. + if (II == 0) return true; + + // If the identifier is a macro, and if that macro is enabled, it may be + // expanded so it's not a trivial expansion. + if (II->hasMacroDefinition() && PP.getMacroInfo(II)->isEnabled() && + // Fast expanding "#define X X" is ok, because X would be disabled. + II != MacroIdent) + return false; + + // If this is an object-like macro invocation, it is safe to trivially expand + // it. + if (MI->isObjectLike()) return true; + + // If this is a function-like macro invocation, it's safe to trivially expand + // as long as the identifier is not a macro argument. + for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); + I != E; ++I) + if (*I == II) + return false; // Identifier is a macro argument. + + return true; +} + + +/// isNextPPTokenLParen - Determine whether the next preprocessor token to be +/// lexed is a '('. If so, consume the token and return true, if not, this +/// method should have no observable side-effect on the lexed tokens. +bool Preprocessor::isNextPPTokenLParen() { + // Do some quick tests for rejection cases. + unsigned Val; + if (CurLexer) + Val = CurLexer->isNextPPTokenLParen(); + else + Val = CurTokenLexer->isNextTokenLParen(); + + if (Val == 2) { + // We have run off the end. If it's a source file we don't + // examine enclosing ones (C99 5.1.1.2p4). Otherwise walk up the + // macro stack. + if (CurLexer) + return false; + for (unsigned i = IncludeMacroStack.size(); i != 0; --i) { + IncludeStackInfo &Entry = IncludeMacroStack[i-1]; + if (Entry.TheLexer) + Val = Entry.TheLexer->isNextPPTokenLParen(); + else + Val = Entry.TheTokenLexer->isNextTokenLParen(); + + if (Val != 2) + break; + + // Ran off the end of a source file? + if (Entry.TheLexer) + return false; + } + } + + // Okay, if we know that the token is a '(', lex it and return. Otherwise we + // have found something that isn't a '(' or we found the end of the + // translation unit. In either case, return false. + if (Val != 1) + return false; + + Token Tok; + LexUnexpandedToken(Tok); + assert(Tok.is(tok::l_paren) && "Error computing l-paren-ness?"); + return true; +} + +/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be +/// expanded as a macro, handle it and return the next token as 'Identifier'. +bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, + MacroInfo *MI) { + // If this is a macro exapnsion in the "#if !defined(x)" line for the file, + // then the macro could expand to different things in other contexts, we need + // to disable the optimization in this case. + if (CurLexer) CurLexer->MIOpt.ExpandedMacro(); + + // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. + if (MI->isBuiltinMacro()) { + ExpandBuiltinMacro(Identifier); + return false; + } + + /// Args - If this is a function-like macro expansion, this contains, + /// for each macro argument, the list of tokens that were provided to the + /// invocation. + MacroArgs *Args = 0; + + // If this is a function-like macro, read the arguments. + if (MI->isFunctionLike()) { + // C99 6.10.3p10: If the preprocessing token immediately after the the macro + // name isn't a '(', this macro should not be expanded. Otherwise, consume + // it. + if (!isNextPPTokenLParen()) + return true; + + // Remember that we are now parsing the arguments to a macro invocation. + // Preprocessor directives used inside macro arguments are not portable, and + // this enables the warning. + InMacroArgs = true; + Args = ReadFunctionLikeMacroArgs(Identifier, MI); + + // Finished parsing args. + InMacroArgs = false; + + // If there was an error parsing the arguments, bail out. + if (Args == 0) return false; + + ++NumFnMacroExpanded; + } else { + ++NumMacroExpanded; + } + + // Notice that this macro has been used. + MI->setIsUsed(true); + + // If we started lexing a macro, enter the macro expansion body. + + // If this macro expands to no tokens, don't bother to push it onto the + // expansion stack, only to take it right back off. + if (MI->getNumTokens() == 0) { + // No need for arg info. + if (Args) Args->destroy(); + + // Ignore this macro use, just return the next token in the current + // buffer. + bool HadLeadingSpace = Identifier.hasLeadingSpace(); + bool IsAtStartOfLine = Identifier.isAtStartOfLine(); + + Lex(Identifier); + + // If the identifier isn't on some OTHER line, inherit the leading + // whitespace/first-on-a-line property of this token. This handles + // stuff like "! XX," -> "! ," and " XX," -> " ,", when XX is + // empty. + if (!Identifier.isAtStartOfLine()) { + if (IsAtStartOfLine) Identifier.setFlag(Token::StartOfLine); + if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace); + } + ++NumFastMacroExpanded; + return false; + + } else if (MI->getNumTokens() == 1 && + isTrivialSingleTokenExpansion(MI, Identifier.getIdentifierInfo(), + *this)){ + // Otherwise, if this macro expands into a single trivially-expanded + // token: expand it now. This handles common cases like + // "#define VAL 42". + + // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro + // identifier to the expanded token. + bool isAtStartOfLine = Identifier.isAtStartOfLine(); + bool hasLeadingSpace = Identifier.hasLeadingSpace(); + + // Remember where the token is instantiated. + SourceLocation InstantiateLoc = Identifier.getLocation(); + + // Replace the result token. + Identifier = MI->getReplacementToken(0); + + // Restore the StartOfLine/LeadingSpace markers. + Identifier.setFlagValue(Token::StartOfLine , isAtStartOfLine); + Identifier.setFlagValue(Token::LeadingSpace, hasLeadingSpace); + + // Update the tokens location to include both its logical and physical + // locations. + SourceLocation Loc = + SourceMgr.getInstantiationLoc(Identifier.getLocation(), InstantiateLoc); + Identifier.setLocation(Loc); + + // If this is #define X X, we must mark the result as unexpandible. + if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) + if (getMacroInfo(NewII) == MI) + Identifier.setFlag(Token::DisableExpand); + + // Since this is not an identifier token, it can't be macro expanded, so + // we're done. + ++NumFastMacroExpanded; + return false; + } + + // Start expanding the macro. + EnterMacro(Identifier, Args); + + // Now that the macro is at the top of the include stack, ask the + // preprocessor to read the next token from it. + Lex(Identifier); + return false; +} + +/// ReadFunctionLikeMacroArgs - After reading "MACRO(", this method is +/// invoked to read all of the actual arguments specified for the macro +/// invocation. This returns null on error. +MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, + MacroInfo *MI) { + // The number of fixed arguments to parse. + unsigned NumFixedArgsLeft = MI->getNumArgs(); + bool isVariadic = MI->isVariadic(); + + // Outer loop, while there are more arguments, keep reading them. + Token Tok; + Tok.setKind(tok::comma); + --NumFixedArgsLeft; // Start reading the first arg. + + // ArgTokens - Build up a list of tokens that make up each argument. Each + // argument is separated by an EOF token. Use a SmallVector so we can avoid + // heap allocations in the common case. + llvm::SmallVector ArgTokens; + + unsigned NumActuals = 0; + while (Tok.is(tok::comma)) { + // C99 6.10.3p11: Keep track of the number of l_parens we have seen. Note + // that we already consumed the first one. + unsigned NumParens = 0; + + while (1) { + // Read arguments as unexpanded tokens. This avoids issues, e.g., where + // an argument value in a macro could expand to ',' or '(' or ')'. + LexUnexpandedToken(Tok); + + if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(" & "#if f(\n" + Diag(MacroName, diag::err_unterm_macro_invoc); + // Do not lose the EOF/EOM. Return it to the client. + MacroName = Tok; + return 0; + } else if (Tok.is(tok::r_paren)) { + // If we found the ) token, the macro arg list is done. + if (NumParens-- == 0) + break; + } else if (Tok.is(tok::l_paren)) { + ++NumParens; + } else if (Tok.is(tok::comma) && NumParens == 0) { + // Comma ends this argument if there are more fixed arguments expected. + if (NumFixedArgsLeft) + break; + + // If this is not a variadic macro, too many args were specified. + if (!isVariadic) { + // Emit the diagnostic at the macro name in case there is a missing ). + // Emitting it at the , could be far away from the macro name. + Diag(MacroName, diag::err_too_many_args_in_macro_invoc); + return 0; + } + // Otherwise, continue to add the tokens to this variable argument. + } else if (Tok.is(tok::comment) && !KeepMacroComments) { + // If this is a comment token in the argument list and we're just in + // -C mode (not -CC mode), discard the comment. + continue; + } else if (Tok.is(tok::identifier)) { + // Reading macro arguments can cause macros that we are currently + // expanding from to be popped off the expansion stack. Doing so causes + // them to be reenabled for expansion. Here we record whether any + // identifiers we lex as macro arguments correspond to disabled macros. + // If so, we mark the token as noexpand. This is a subtle aspect of + // C99 6.10.3.4p2. + if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo())) + if (!MI->isEnabled()) + Tok.setFlag(Token::DisableExpand); + } + + ArgTokens.push_back(Tok); + } + + // Empty arguments are standard in C99 and supported as an extension in + // other modes. + if (ArgTokens.empty() && !Features.C99) + Diag(Tok, diag::ext_empty_fnmacro_arg); + + // Add a marker EOF token to the end of the token list for this argument. + Token EOFTok; + EOFTok.startToken(); + EOFTok.setKind(tok::eof); + EOFTok.setLocation(Tok.getLocation()); + EOFTok.setLength(0); + ArgTokens.push_back(EOFTok); + ++NumActuals; + --NumFixedArgsLeft; + }; + + // Okay, we either found the r_paren. Check to see if we parsed too few + // arguments. + unsigned MinArgsExpected = MI->getNumArgs(); + + // See MacroArgs instance var for description of this. + bool isVarargsElided = false; + + if (NumActuals < MinArgsExpected) { + // There are several cases where too few arguments is ok, handle them now. + if (NumActuals+1 == MinArgsExpected && MI->isVariadic()) { + // Varargs where the named vararg parameter is missing: ok as extension. + // #define A(x, ...) + // A("blah") + Diag(Tok, diag::ext_missing_varargs_arg); + + // Remember this occurred if this is a C99 macro invocation with at least + // one actual argument. + isVarargsElided = MI->isC99Varargs() && MI->getNumArgs() > 1; + } else if (MI->getNumArgs() == 1) { + // #define A(x) + // A() + // is ok because it is an empty argument. + + // Empty arguments are standard in C99 and supported as an extension in + // other modes. + if (ArgTokens.empty() && !Features.C99) + Diag(Tok, diag::ext_empty_fnmacro_arg); + } else { + // Otherwise, emit the error. + Diag(Tok, diag::err_too_few_args_in_macro_invoc); + return 0; + } + + // Add a marker EOF token to the end of the token list for this argument. + SourceLocation EndLoc = Tok.getLocation(); + Tok.startToken(); + Tok.setKind(tok::eof); + Tok.setLocation(EndLoc); + Tok.setLength(0); + ArgTokens.push_back(Tok); + } + + return MacroArgs::create(MI, &ArgTokens[0], ArgTokens.size(),isVarargsElided); +} + +/// ComputeDATE_TIME - Compute the current time, enter it into the specified +/// scratch buffer, then return DATELoc/TIMELoc locations with the position of +/// the identifier tokens inserted. +static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, + Preprocessor &PP) { + time_t TT = time(0); + struct tm *TM = localtime(&TT); + + static const char * const Months[] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" + }; + + char TmpBuffer[100]; + sprintf(TmpBuffer, "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday, + TM->tm_year+1900); + DATELoc = PP.CreateString(TmpBuffer, strlen(TmpBuffer)); + + sprintf(TmpBuffer, "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec); + TIMELoc = PP.CreateString(TmpBuffer, strlen(TmpBuffer)); +} + +/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded +/// as a builtin macro, handle it and return the next token as 'Tok'. +void Preprocessor::ExpandBuiltinMacro(Token &Tok) { + // Figure out which token this is. + IdentifierInfo *II = Tok.getIdentifierInfo(); + assert(II && "Can't be a macro without id info!"); + + // If this is an _Pragma directive, expand it, invoke the pragma handler, then + // lex the token after it. + if (II == Ident_Pragma) + return Handle_Pragma(Tok); + + ++NumBuiltinMacroExpanded; + + char TmpBuffer[100]; + + // Set up the return result. + Tok.setIdentifierInfo(0); + Tok.clearFlag(Token::NeedsCleaning); + + if (II == Ident__LINE__) { + // __LINE__ expands to a simple numeric value. + sprintf(TmpBuffer, "%u", SourceMgr.getLogicalLineNumber(Tok.getLocation())); + unsigned Length = strlen(TmpBuffer); + Tok.setKind(tok::numeric_constant); + Tok.setLength(Length); + Tok.setLocation(CreateString(TmpBuffer, Length, Tok.getLocation())); + } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { + SourceLocation Loc = Tok.getLocation(); + if (II == Ident__BASE_FILE__) { + Diag(Tok, diag::ext_pp_base_file); + SourceLocation NextLoc = SourceMgr.getIncludeLoc(Loc); + while (NextLoc.isValid()) { + Loc = NextLoc; + NextLoc = SourceMgr.getIncludeLoc(Loc); + } + } + + // Escape this filename. Turn '\' -> '\\' '"' -> '\"' + std::string FN = SourceMgr.getSourceName(SourceMgr.getLogicalLoc(Loc)); + FN = '"' + Lexer::Stringify(FN) + '"'; + Tok.setKind(tok::string_literal); + Tok.setLength(FN.size()); + Tok.setLocation(CreateString(&FN[0], FN.size(), Tok.getLocation())); + } else if (II == Ident__DATE__) { + if (!DATELoc.isValid()) + ComputeDATE_TIME(DATELoc, TIMELoc, *this); + Tok.setKind(tok::string_literal); + Tok.setLength(strlen("\"Mmm dd yyyy\"")); + Tok.setLocation(SourceMgr.getInstantiationLoc(DATELoc, Tok.getLocation())); + } else if (II == Ident__TIME__) { + if (!TIMELoc.isValid()) + ComputeDATE_TIME(DATELoc, TIMELoc, *this); + Tok.setKind(tok::string_literal); + Tok.setLength(strlen("\"hh:mm:ss\"")); + Tok.setLocation(SourceMgr.getInstantiationLoc(TIMELoc, Tok.getLocation())); + } else if (II == Ident__INCLUDE_LEVEL__) { + Diag(Tok, diag::ext_pp_include_level); + + // Compute the include depth of this token. + unsigned Depth = 0; + SourceLocation Loc = SourceMgr.getIncludeLoc(Tok.getLocation()); + for (; Loc.isValid(); ++Depth) + Loc = SourceMgr.getIncludeLoc(Loc); + + // __INCLUDE_LEVEL__ expands to a simple numeric value. + sprintf(TmpBuffer, "%u", Depth); + unsigned Length = strlen(TmpBuffer); + Tok.setKind(tok::numeric_constant); + Tok.setLength(Length); + Tok.setLocation(CreateString(TmpBuffer, Length, Tok.getLocation())); + } else if (II == Ident__TIMESTAMP__) { + // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be + // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. + Diag(Tok, diag::ext_pp_timestamp); + + // Get the file that we are lexing out of. If we're currently lexing from + // a macro, dig into the include stack. + const FileEntry *CurFile = 0; + Lexer *TheLexer = getCurrentFileLexer(); + + if (TheLexer) + CurFile = SourceMgr.getFileEntryForLoc(TheLexer->getFileLoc()); + + // If this file is older than the file it depends on, emit a diagnostic. + const char *Result; + if (CurFile) { + time_t TT = CurFile->getModificationTime(); + struct tm *TM = localtime(&TT); + Result = asctime(TM); + } else { + Result = "??? ??? ?? ??:??:?? ????\n"; + } + TmpBuffer[0] = '"'; + strcpy(TmpBuffer+1, Result); + unsigned Len = strlen(TmpBuffer); + TmpBuffer[Len-1] = '"'; // Replace the newline with a quote. + Tok.setKind(tok::string_literal); + Tok.setLength(Len); + Tok.setLocation(CreateString(TmpBuffer, Len, Tok.getLocation())); + } else { + assert(0 && "Unknown identifier!"); + } +} diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp new file mode 100644 index 00000000000..08ad1cf1d2f --- /dev/null +++ b/clang/lib/Lex/Pragma.cpp @@ -0,0 +1,386 @@ +//===--- Pragma.cpp - Pragma registration and handling --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PragmaHandler/PragmaTable interfaces and implements +// pragma related methods of the Preprocessor class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Pragma.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/SmallVector.h" +using namespace clang; + +// Out-of-line destructor to provide a home for the class. +PragmaHandler::~PragmaHandler() { +} + +//===----------------------------------------------------------------------===// +// PragmaNamespace Implementation. +//===----------------------------------------------------------------------===// + + +PragmaNamespace::~PragmaNamespace() { + for (unsigned i = 0, e = Handlers.size(); i != e; ++i) + delete Handlers[i]; +} + +/// FindHandler - Check to see if there is already a handler for the +/// specified name. If not, return the handler for the null identifier if it +/// exists, otherwise return null. If IgnoreNull is true (the default) then +/// the null handler isn't returned on failure to match. +PragmaHandler *PragmaNamespace::FindHandler(const IdentifierInfo *Name, + bool IgnoreNull) const { + PragmaHandler *NullHandler = 0; + for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { + if (Handlers[i]->getName() == Name) + return Handlers[i]; + + if (Handlers[i]->getName() == 0) + NullHandler = Handlers[i]; + } + return IgnoreNull ? 0 : NullHandler; +} + +void PragmaNamespace::HandlePragma(Preprocessor &PP, Token &Tok) { + // Read the 'namespace' that the directive is in, e.g. STDC. Do not macro + // expand it, the user can have a STDC #define, that should not affect this. + PP.LexUnexpandedToken(Tok); + + // Get the handler for this token. If there is no handler, ignore the pragma. + PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false); + if (Handler == 0) return; + + // Otherwise, pass it down. + Handler->HandlePragma(PP, Tok); +} + +//===----------------------------------------------------------------------===// +// Preprocessor Pragma Directive Handling. +//===----------------------------------------------------------------------===// + +/// HandlePragmaDirective - The "#pragma" directive has been parsed. Lex the +/// rest of the pragma, passing it to the registered pragma handlers. +void Preprocessor::HandlePragmaDirective() { + ++NumPragma; + + // Invoke the first level of pragma handlers which reads the namespace id. + Token Tok; + PragmaHandlers->HandlePragma(*this, Tok); + + // If the pragma handler didn't read the rest of the line, consume it now. + if (CurLexer->ParsingPreprocessorDirective) + DiscardUntilEndOfDirective(); +} + +/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then +/// return the first token after the directive. The _Pragma token has just +/// been read into 'Tok'. +void Preprocessor::Handle_Pragma(Token &Tok) { + // Remember the pragma token location. + SourceLocation PragmaLoc = Tok.getLocation(); + + // Read the '('. + Lex(Tok); + if (Tok.isNot(tok::l_paren)) + return Diag(PragmaLoc, diag::err__Pragma_malformed); + + // Read the '"..."'. + Lex(Tok); + if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) + return Diag(PragmaLoc, diag::err__Pragma_malformed); + + // Remember the string. + std::string StrVal = getSpelling(Tok); + SourceLocation StrLoc = Tok.getLocation(); + + // Read the ')'. + Lex(Tok); + if (Tok.isNot(tok::r_paren)) + return Diag(PragmaLoc, diag::err__Pragma_malformed); + + // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1. + if (StrVal[0] == 'L') // Remove L prefix. + StrVal.erase(StrVal.begin()); + assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && + "Invalid string token!"); + + // Remove the front quote, replacing it with a space, so that the pragma + // contents appear to have a space before them. + StrVal[0] = ' '; + + // Replace the terminating quote with a \n\0. + StrVal[StrVal.size()-1] = '\n'; + StrVal += '\0'; + + // Remove escaped quotes and escapes. + for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) { + if (StrVal[i] == '\\' && + (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) { + // \\ -> '\' and \" -> '"'. + StrVal.erase(StrVal.begin()+i); + --e; + } + } + + // Plop the string (including the newline and trailing null) into a buffer + // where we can lex it. + SourceLocation TokLoc = CreateString(&StrVal[0], StrVal.size(), StrLoc); + const char *StrData = SourceMgr.getCharacterData(TokLoc); + + // Make and enter a lexer object so that we lex and expand the tokens just + // like any others. + Lexer *TL = new Lexer(TokLoc, *this, + StrData, StrData+StrVal.size()-1 /* no null */); + + // Ensure that the lexer thinks it is inside a directive, so that end \n will + // return an EOM token. + TL->ParsingPreprocessorDirective = true; + + // This lexer really is for _Pragma. + TL->Is_PragmaLexer = true; + + EnterSourceFileWithLexer(TL, 0); + + // With everything set up, lex this as a #pragma directive. + HandlePragmaDirective(); + + // Finally, return whatever came after the pragma directive. + return Lex(Tok); +} + + + +/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'. +/// +void Preprocessor::HandlePragmaOnce(Token &OnceTok) { + if (isInPrimaryFile()) { + Diag(OnceTok, diag::pp_pragma_once_in_main_file); + return; + } + + // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. + SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc(); + + // Mark the file as a once-only file now. + HeaderInfo.MarkFileIncludeOnce(SourceMgr.getFileEntryForLoc(FileLoc)); +} + +void Preprocessor::HandlePragmaMark() { + assert(CurLexer && "No current lexer?"); + CurLexer->ReadToEndOfLine(); +} + + +/// HandlePragmaPoison - Handle #pragma GCC poison. PoisonTok is the 'poison'. +/// +void Preprocessor::HandlePragmaPoison(Token &PoisonTok) { + Token Tok; + + while (1) { + // Read the next token to poison. While doing this, pretend that we are + // skipping while reading the identifier to poison. + // This avoids errors on code like: + // #pragma GCC poison X + // #pragma GCC poison X + if (CurLexer) CurLexer->LexingRawMode = true; + LexUnexpandedToken(Tok); + if (CurLexer) CurLexer->LexingRawMode = false; + + // If we reached the end of line, we're done. + if (Tok.is(tok::eom)) return; + + // Can only poison identifiers. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_pp_invalid_poison); + return; + } + + // Look up the identifier info for the token. We disabled identifier lookup + // by saying we're skipping contents, so we need to do this manually. + IdentifierInfo *II = LookUpIdentifierInfo(Tok); + + // Already poisoned. + if (II->isPoisoned()) continue; + + // If this is a macro identifier, emit a warning. + if (II->hasMacroDefinition()) + Diag(Tok, diag::pp_poisoning_existing_macro); + + // Finally, poison it! + II->setIsPoisoned(); + } +} + +/// HandlePragmaSystemHeader - Implement #pragma GCC system_header. We know +/// that the whole directive has been parsed. +void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { + if (isInPrimaryFile()) { + Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file); + return; + } + + // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. + Lexer *TheLexer = getCurrentFileLexer(); + + // Mark the file as a system header. + const FileEntry *File = SourceMgr.getFileEntryForLoc(TheLexer->getFileLoc()); + HeaderInfo.MarkFileSystemHeader(File); + + // Notify the client, if desired, that we are in a new source file. + if (Callbacks) + Callbacks->FileChanged(TheLexer->getSourceLocation(TheLexer->BufferPtr), + PPCallbacks::SystemHeaderPragma, + DirectoryLookup::SystemHeaderDir); +} + +/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah. +/// +void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { + Token FilenameTok; + CurLexer->LexIncludeFilename(FilenameTok); + + // If the token kind is EOM, the error has already been diagnosed. + if (FilenameTok.is(tok::eom)) + return; + + // Reserve a buffer to get the spelling. + llvm::SmallVector FilenameBuffer; + FilenameBuffer.resize(FilenameTok.getLength()); + + const char *FilenameStart = &FilenameBuffer[0]; + unsigned Len = getSpelling(FilenameTok, FilenameStart); + const char *FilenameEnd = FilenameStart+Len; + bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), + FilenameStart, FilenameEnd); + // If GetIncludeFilenameSpelling set the start ptr to null, there was an + // error. + if (FilenameStart == 0) + return; + + // Search include directories for this file. + const DirectoryLookup *CurDir; + const FileEntry *File = LookupFile(FilenameStart, FilenameEnd, + isAngled, 0, CurDir); + if (File == 0) + return Diag(FilenameTok, diag::err_pp_file_not_found, + std::string(FilenameStart, FilenameEnd)); + + SourceLocation FileLoc = getCurrentFileLexer()->getFileLoc(); + const FileEntry *CurFile = SourceMgr.getFileEntryForLoc(FileLoc); + + // If this file is older than the file it depends on, emit a diagnostic. + if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) { + // Lex tokens at the end of the message and include them in the message. + std::string Message; + Lex(DependencyTok); + while (DependencyTok.isNot(tok::eom)) { + Message += getSpelling(DependencyTok) + " "; + Lex(DependencyTok); + } + + Message.erase(Message.end()-1); + Diag(FilenameTok, diag::pp_out_of_date_dependency, Message); + } +} + + +/// AddPragmaHandler - Add the specified pragma handler to the preprocessor. +/// If 'Namespace' is non-null, then it is a token required to exist on the +/// pragma line before the pragma string starts, e.g. "STDC" or "GCC". +void Preprocessor::AddPragmaHandler(const char *Namespace, + PragmaHandler *Handler) { + PragmaNamespace *InsertNS = PragmaHandlers; + + // If this is specified to be in a namespace, step down into it. + if (Namespace) { + IdentifierInfo *NSID = getIdentifierInfo(Namespace); + + // If there is already a pragma handler with the name of this namespace, + // we either have an error (directive with the same name as a namespace) or + // we already have the namespace to insert into. + if (PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID)) { + InsertNS = Existing->getIfNamespace(); + assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma" + " handler with the same name!"); + } else { + // Otherwise, this namespace doesn't exist yet, create and insert the + // handler for it. + InsertNS = new PragmaNamespace(NSID); + PragmaHandlers->AddPragma(InsertNS); + } + } + + // Check to make sure we don't already have a pragma for this identifier. + assert(!InsertNS->FindHandler(Handler->getName()) && + "Pragma handler already exists for this identifier!"); + InsertNS->AddPragma(Handler); +} + +namespace { +/// PragmaOnceHandler - "#pragma once" marks the file as atomically included. +struct PragmaOnceHandler : public PragmaHandler { + PragmaOnceHandler(const IdentifierInfo *OnceID) : PragmaHandler(OnceID) {} + virtual void HandlePragma(Preprocessor &PP, Token &OnceTok) { + PP.CheckEndOfDirective("#pragma once"); + PP.HandlePragmaOnce(OnceTok); + } +}; + +/// PragmaMarkHandler - "#pragma mark ..." is ignored by the compiler, and the +/// rest of the line is not lexed. +struct PragmaMarkHandler : public PragmaHandler { + PragmaMarkHandler(const IdentifierInfo *MarkID) : PragmaHandler(MarkID) {} + virtual void HandlePragma(Preprocessor &PP, Token &MarkTok) { + PP.HandlePragmaMark(); + } +}; + +/// PragmaPoisonHandler - "#pragma poison x" marks x as not usable. +struct PragmaPoisonHandler : public PragmaHandler { + PragmaPoisonHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} + virtual void HandlePragma(Preprocessor &PP, Token &PoisonTok) { + PP.HandlePragmaPoison(PoisonTok); + } +}; + +/// PragmaSystemHeaderHandler - "#pragma system_header" marks the current file +/// as a system header, which silences warnings in it. +struct PragmaSystemHeaderHandler : public PragmaHandler { + PragmaSystemHeaderHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} + virtual void HandlePragma(Preprocessor &PP, Token &SHToken) { + PP.HandlePragmaSystemHeader(SHToken); + PP.CheckEndOfDirective("#pragma"); + } +}; +struct PragmaDependencyHandler : public PragmaHandler { + PragmaDependencyHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} + virtual void HandlePragma(Preprocessor &PP, Token &DepToken) { + PP.HandlePragmaDependency(DepToken); + } +}; +} // end anonymous namespace + + +/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: +/// #pragma GCC poison/system_header/dependency and #pragma once. +void Preprocessor::RegisterBuiltinPragmas() { + AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once"))); + AddPragmaHandler(0, new PragmaMarkHandler(getIdentifierInfo("mark"))); + AddPragmaHandler("GCC", new PragmaPoisonHandler(getIdentifierInfo("poison"))); + AddPragmaHandler("GCC", new PragmaSystemHeaderHandler( + getIdentifierInfo("system_header"))); + AddPragmaHandler("GCC", new PragmaDependencyHandler( + getIdentifierInfo("dependency"))); +} diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp new file mode 100644 index 00000000000..86156a07728 --- /dev/null +++ b/clang/lib/Lex/Preprocessor.cpp @@ -0,0 +1,560 @@ +//===--- Preprocess.cpp - C Language Family Preprocessor Implementation ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Preprocessor interface. +// +//===----------------------------------------------------------------------===// +// +// Options to support: +// -H - Print the name of each header file used. +// -d[MDNI] - Dump various things. +// -fworking-directory - #line's with preprocessor's working dir. +// -fpreprocessed +// -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD +// -W* +// -w +// +// Messages to emit: +// "Multiple include guards may be useful for:\n" +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Pragma.h" +#include "clang/Lex/ScratchBuffer.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Streams.h" +#include +using namespace clang; + +//===----------------------------------------------------------------------===// + +Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, + TargetInfo &target, SourceManager &SM, + HeaderSearch &Headers) + : Diags(diags), Features(opts), Target(target), FileMgr(Headers.getFileMgr()), + SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts), + CurLexer(0), CurDirLookup(0), CurTokenLexer(0), Callbacks(0) { + ScratchBuf = new ScratchBuffer(SourceMgr); + + // Clear stats. + NumDirectives = NumDefined = NumUndefined = NumPragma = 0; + NumIf = NumElse = NumEndif = 0; + NumEnteredSourceFiles = 0; + NumMacroExpanded = NumFnMacroExpanded = NumBuiltinMacroExpanded = 0; + NumFastMacroExpanded = NumTokenPaste = NumFastTokenPaste = 0; + MaxIncludeStackDepth = 0; + NumSkipped = 0; + + // Default to discarding comments. + KeepComments = false; + KeepMacroComments = false; + + // Macro expansion is enabled. + DisableMacroExpansion = false; + InMacroArgs = false; + NumCachedTokenLexers = 0; + + // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. + // This gets unpoisoned where it is allowed. + (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); + + Predefines = 0; + + // Initialize the pragma handlers. + PragmaHandlers = new PragmaNamespace(0); + RegisterBuiltinPragmas(); + + // Initialize builtin macros like __LINE__ and friends. + RegisterBuiltinMacros(); +} + +Preprocessor::~Preprocessor() { + // Free any active lexers. + delete CurLexer; + + while (!IncludeMacroStack.empty()) { + delete IncludeMacroStack.back().TheLexer; + delete IncludeMacroStack.back().TheTokenLexer; + IncludeMacroStack.pop_back(); + } + + // Free any macro definitions. + for (llvm::DenseMap::iterator I = + Macros.begin(), E = Macros.end(); I != E; ++I) { + // Free the macro definition. + delete I->second; + I->second = 0; + I->first->setHasMacroDefinition(false); + } + + // Free any cached macro expanders. + for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) + delete TokenLexerCache[i]; + + // Release pragma information. + delete PragmaHandlers; + + // Delete the scratch buffer info. + delete ScratchBuf; + + delete Callbacks; +} + +/// Diag - Forwarding function for diagnostics. This emits a diagnostic at +/// the specified Token's location, translating the token's start +/// position in the current buffer into a SourcePosition object for rendering. +void Preprocessor::Diag(SourceLocation Loc, unsigned DiagID) { + Diags.Report(getFullLoc(Loc), DiagID); +} + +void Preprocessor::Diag(SourceLocation Loc, unsigned DiagID, + const std::string &Msg) { + Diags.Report(getFullLoc(Loc), DiagID, &Msg, 1); +} + +void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { + llvm::cerr << tok::getTokenName(Tok.getKind()) << " '" + << getSpelling(Tok) << "'"; + + if (!DumpFlags) return; + + llvm::cerr << "\t"; + if (Tok.isAtStartOfLine()) + llvm::cerr << " [StartOfLine]"; + if (Tok.hasLeadingSpace()) + llvm::cerr << " [LeadingSpace]"; + if (Tok.isExpandDisabled()) + llvm::cerr << " [ExpandDisabled]"; + if (Tok.needsCleaning()) { + const char *Start = SourceMgr.getCharacterData(Tok.getLocation()); + llvm::cerr << " [UnClean='" << std::string(Start, Start+Tok.getLength()) + << "']"; + } + + llvm::cerr << "\tLoc=<"; + DumpLocation(Tok.getLocation()); + llvm::cerr << ">"; +} + +void Preprocessor::DumpLocation(SourceLocation Loc) const { + SourceLocation LogLoc = SourceMgr.getLogicalLoc(Loc); + llvm::cerr << SourceMgr.getSourceName(LogLoc) << ':' + << SourceMgr.getLineNumber(LogLoc) << ':' + << SourceMgr.getLineNumber(LogLoc); + + SourceLocation PhysLoc = SourceMgr.getPhysicalLoc(Loc); + if (PhysLoc != LogLoc) { + llvm::cerr << " "; + } +} + +void Preprocessor::DumpMacro(const MacroInfo &MI) const { + llvm::cerr << "MACRO: "; + for (unsigned i = 0, e = MI.getNumTokens(); i != e; ++i) { + DumpToken(MI.getReplacementToken(i)); + llvm::cerr << " "; + } + llvm::cerr << "\n"; +} + +void Preprocessor::PrintStats() { + llvm::cerr << "\n*** Preprocessor Stats:\n"; + llvm::cerr << NumDirectives << " directives found:\n"; + llvm::cerr << " " << NumDefined << " #define.\n"; + llvm::cerr << " " << NumUndefined << " #undef.\n"; + llvm::cerr << " #include/#include_next/#import:\n"; + llvm::cerr << " " << NumEnteredSourceFiles << " source files entered.\n"; + llvm::cerr << " " << MaxIncludeStackDepth << " max include stack depth\n"; + llvm::cerr << " " << NumIf << " #if/#ifndef/#ifdef.\n"; + llvm::cerr << " " << NumElse << " #else/#elif.\n"; + llvm::cerr << " " << NumEndif << " #endif.\n"; + llvm::cerr << " " << NumPragma << " #pragma.\n"; + llvm::cerr << NumSkipped << " #if/#ifndef#ifdef regions skipped\n"; + + llvm::cerr << NumMacroExpanded << "/" << NumFnMacroExpanded << "/" + << NumBuiltinMacroExpanded << " obj/fn/builtin macros expanded, " + << NumFastMacroExpanded << " on the fast path.\n"; + llvm::cerr << (NumFastTokenPaste+NumTokenPaste) + << " token paste (##) operations performed, " + << NumFastTokenPaste << " on the fast path.\n"; +} + +//===----------------------------------------------------------------------===// +// Token Spelling +//===----------------------------------------------------------------------===// + + +/// getSpelling() - Return the 'spelling' of this token. The spelling of a +/// token are the characters used to represent the token in the source file +/// after trigraph expansion and escaped-newline folding. In particular, this +/// wants to get the true, uncanonicalized, spelling of things like digraphs +/// UCNs, etc. +std::string Preprocessor::getSpelling(const Token &Tok) const { + assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); + + // If this token contains nothing interesting, return it directly. + const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation()); + if (!Tok.needsCleaning()) + return std::string(TokStart, TokStart+Tok.getLength()); + + std::string Result; + Result.reserve(Tok.getLength()); + + // Otherwise, hard case, relex the characters into the string. + for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength(); + Ptr != End; ) { + unsigned CharSize; + Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features)); + Ptr += CharSize; + } + assert(Result.size() != unsigned(Tok.getLength()) && + "NeedsCleaning flag set on something that didn't need cleaning!"); + return Result; +} + +/// getSpelling - This method is used to get the spelling of a token into a +/// preallocated buffer, instead of as an std::string. The caller is required +/// to allocate enough space for the token, which is guaranteed to be at least +/// Tok.getLength() bytes long. The actual length of the token is returned. +/// +/// Note that this method may do two possible things: it may either fill in +/// the buffer specified with characters, or it may *change the input pointer* +/// to point to a constant buffer with the data already in it (avoiding a +/// copy). The caller is not allowed to modify the returned buffer pointer +/// if an internal buffer is returned. +unsigned Preprocessor::getSpelling(const Token &Tok, + const char *&Buffer) const { + assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); + + // If this token is an identifier, just return the string from the identifier + // table, which is very quick. + if (const IdentifierInfo *II = Tok.getIdentifierInfo()) { + Buffer = II->getName(); + + // Return the length of the token. If the token needed cleaning, don't + // include the size of the newlines or trigraphs in it. + if (!Tok.needsCleaning()) + return Tok.getLength(); + else + return strlen(Buffer); + } + + // Otherwise, compute the start of the token in the input lexer buffer. + const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation()); + + // If this token contains nothing interesting, return it directly. + if (!Tok.needsCleaning()) { + Buffer = TokStart; + return Tok.getLength(); + } + // Otherwise, hard case, relex the characters into the string. + char *OutBuf = const_cast(Buffer); + for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength(); + Ptr != End; ) { + unsigned CharSize; + *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, Features); + Ptr += CharSize; + } + assert(unsigned(OutBuf-Buffer) != Tok.getLength() && + "NeedsCleaning flag set on something that didn't need cleaning!"); + + return OutBuf-Buffer; +} + + +/// CreateString - Plop the specified string into a scratch buffer and return a +/// location for it. If specified, the source location provides a source +/// location for the token. +SourceLocation Preprocessor:: +CreateString(const char *Buf, unsigned Len, SourceLocation SLoc) { + if (SLoc.isValid()) + return ScratchBuf->getToken(Buf, Len, SLoc); + return ScratchBuf->getToken(Buf, Len); +} + + +/// AdvanceToTokenCharacter - Given a location that specifies the start of a +/// token, return a new location that specifies a character within the token. +SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned CharNo) { + // If they request the first char of the token, we're trivially done. If this + // is a macro expansion, it doesn't make sense to point to a character within + // the instantiation point (the name). We could point to the source + // character, but without also pointing to instantiation info, this is + // confusing. + if (CharNo == 0 || TokStart.isMacroID()) return TokStart; + + // Figure out how many physical characters away the specified logical + // character is. This needs to take into consideration newlines and + // trigraphs. + const char *TokPtr = SourceMgr.getCharacterData(TokStart); + unsigned PhysOffset = 0; + + // The usual case is that tokens don't contain anything interesting. Skip + // over the uninteresting characters. If a token only consists of simple + // chars, this method is extremely fast. + while (CharNo && Lexer::isObviouslySimpleCharacter(*TokPtr)) + ++TokPtr, --CharNo, ++PhysOffset; + + // If we have a character that may be a trigraph or escaped newline, create a + // lexer to parse it correctly. + if (CharNo != 0) { + // Create a lexer starting at this token position. + Lexer TheLexer(TokStart, *this, TokPtr); + Token Tok; + // Skip over characters the remaining characters. + const char *TokStartPtr = TokPtr; + for (; CharNo; --CharNo) + TheLexer.getAndAdvanceChar(TokPtr, Tok); + + PhysOffset += TokPtr-TokStartPtr; + } + + return TokStart.getFileLocWithOffset(PhysOffset); +} + + +//===----------------------------------------------------------------------===// +// Preprocessor Initialization Methods +//===----------------------------------------------------------------------===// + +// Append a #define line to Buf for Macro. Macro should be of the form XXX, +// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit +// "#define XXX Y z W". To get a #define with no value, use "XXX=". +static void DefineBuiltinMacro(std::vector &Buf, const char *Macro, + const char *Command = "#define ") { + Buf.insert(Buf.end(), Command, Command+strlen(Command)); + if (const char *Equal = strchr(Macro, '=')) { + // Turn the = into ' '. + Buf.insert(Buf.end(), Macro, Equal); + Buf.push_back(' '); + Buf.insert(Buf.end(), Equal+1, Equal+strlen(Equal)); + } else { + // Push "macroname 1". + Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); + Buf.push_back(' '); + Buf.push_back('1'); + } + Buf.push_back('\n'); +} + + +static void InitializePredefinedMacros(Preprocessor &PP, + std::vector &Buf) { + // FIXME: Implement magic like cpp_init_builtins for things like __STDC__ + // and __DATE__ etc. +#if 0 + /* __STDC__ has the value 1 under normal circumstances. + However, if (a) we are in a system header, (b) the option + stdc_0_in_system_headers is true (set by target config), and + (c) we are not in strictly conforming mode, then it has the + value 0. (b) and (c) are already checked in cpp_init_builtins. */ + //case BT_STDC: + if (cpp_in_system_header (pfile)) + number = 0; + else + number = 1; + break; +#endif + // These should all be defined in the preprocessor according to the + // current language configuration. + DefineBuiltinMacro(Buf, "__STDC__=1"); + //DefineBuiltinMacro(Buf, "__ASSEMBLER__=1"); + if (PP.getLangOptions().C99 && !PP.getLangOptions().CPlusPlus) + DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L"); + else if (0) // STDC94 ? + DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L"); + + DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1"); + if (PP.getLangOptions().ObjC1) + DefineBuiltinMacro(Buf, "__OBJC__=1"); + if (PP.getLangOptions().ObjC2) + DefineBuiltinMacro(Buf, "__OBJC2__=1"); + + // Add __builtin_va_list typedef. + { + const char *VAList = PP.getTargetInfo().getVAListDeclaration(); + Buf.insert(Buf.end(), VAList, VAList+strlen(VAList)); + Buf.push_back('\n'); + } + + // Get the target #defines. + PP.getTargetInfo().getTargetDefines(Buf); + + // Compiler set macros. + DefineBuiltinMacro(Buf, "__APPLE_CC__=5250"); + DefineBuiltinMacro(Buf, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1050"); + DefineBuiltinMacro(Buf, "__GNUC_MINOR__=0"); + DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1"); + DefineBuiltinMacro(Buf, "__GNUC__=4"); + DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002"); + DefineBuiltinMacro(Buf, "__VERSION__=\"4.0.1 (Apple Computer, Inc. " + "build 5250)\""); + + // Build configuration options. + DefineBuiltinMacro(Buf, "__DYNAMIC__=1"); + DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0"); + DefineBuiltinMacro(Buf, "__NO_INLINE__=1"); + DefineBuiltinMacro(Buf, "__PIC__=1"); + + + if (PP.getLangOptions().CPlusPlus) { + DefineBuiltinMacro(Buf, "__DEPRECATED=1"); + DefineBuiltinMacro(Buf, "__EXCEPTIONS=1"); + DefineBuiltinMacro(Buf, "__GNUG__=4"); + DefineBuiltinMacro(Buf, "__GXX_WEAK__=1"); + DefineBuiltinMacro(Buf, "__cplusplus=1"); + DefineBuiltinMacro(Buf, "__private_extern__=extern"); + } + if (PP.getLangOptions().Microsoft) { + DefineBuiltinMacro(Buf, "__stdcall="); + DefineBuiltinMacro(Buf, "__cdecl="); + DefineBuiltinMacro(Buf, "_cdecl="); + DefineBuiltinMacro(Buf, "__ptr64="); + DefineBuiltinMacro(Buf, "__w64="); + DefineBuiltinMacro(Buf, "__forceinline="); + DefineBuiltinMacro(Buf, "__int8=char"); + DefineBuiltinMacro(Buf, "__int16=short"); + DefineBuiltinMacro(Buf, "__int32=int"); + DefineBuiltinMacro(Buf, "__int64=long long"); + DefineBuiltinMacro(Buf, "__declspec(X)="); + } + // FIXME: Should emit a #line directive here. +} + + +/// EnterMainSourceFile - Enter the specified FileID as the main source file, +/// which implicitly adds the builtin defines etc. +void Preprocessor::EnterMainSourceFile() { + + unsigned MainFileID = SourceMgr.getMainFileID(); + + // Enter the main file source buffer. + EnterSourceFile(MainFileID, 0); + + // Tell the header info that the main file was entered. If the file is later + // #imported, it won't be re-entered. + if (const FileEntry *FE = + SourceMgr.getFileEntryForLoc(SourceLocation::getFileLoc(MainFileID, 0))) + HeaderInfo.IncrementIncludeCount(FE); + + std::vector PrologFile; + PrologFile.reserve(4080); + + // Install things like __POWERPC__, __GNUC__, etc into the macro table. + InitializePredefinedMacros(*this, PrologFile); + + // Add on the predefines from the driver. + PrologFile.insert(PrologFile.end(), Predefines,Predefines+strlen(Predefines)); + + // Memory buffer must end with a null byte! + PrologFile.push_back(0); + + // Now that we have emitted the predefined macros, #includes, etc into + // PrologFile, preprocess it to populate the initial preprocessor state. + llvm::MemoryBuffer *SB = + llvm::MemoryBuffer::getMemBufferCopy(&PrologFile.front(),&PrologFile.back(), + ""); + assert(SB && "Cannot fail to create predefined source buffer"); + unsigned FileID = SourceMgr.createFileIDForMemBuffer(SB); + assert(FileID && "Could not create FileID for predefines?"); + + // Start parsing the predefines. + EnterSourceFile(FileID, 0); +} + + +//===----------------------------------------------------------------------===// +// Lexer Event Handling. +//===----------------------------------------------------------------------===// + +/// LookUpIdentifierInfo - Given a tok::identifier token, look up the +/// identifier information for the token and install it into the token. +IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier, + const char *BufPtr) { + assert(Identifier.is(tok::identifier) && "Not an identifier!"); + assert(Identifier.getIdentifierInfo() == 0 && "Identinfo already exists!"); + + // Look up this token, see if it is a macro, or if it is a language keyword. + IdentifierInfo *II; + if (BufPtr && !Identifier.needsCleaning()) { + // No cleaning needed, just use the characters from the lexed buffer. + II = getIdentifierInfo(BufPtr, BufPtr+Identifier.getLength()); + } else { + // Cleaning needed, alloca a buffer, clean into it, then use the buffer. + llvm::SmallVector IdentifierBuffer; + IdentifierBuffer.resize(Identifier.getLength()); + const char *TmpBuf = &IdentifierBuffer[0]; + unsigned Size = getSpelling(Identifier, TmpBuf); + II = getIdentifierInfo(TmpBuf, TmpBuf+Size); + } + Identifier.setIdentifierInfo(II); + return II; +} + + +/// HandleIdentifier - This callback is invoked when the lexer reads an +/// identifier. This callback looks up the identifier in the map and/or +/// potentially macro expands it or turns it into a named token (like 'for'). +void Preprocessor::HandleIdentifier(Token &Identifier) { + assert(Identifier.getIdentifierInfo() && + "Can't handle identifiers without identifier info!"); + + IdentifierInfo &II = *Identifier.getIdentifierInfo(); + + // If this identifier was poisoned, and if it was not produced from a macro + // expansion, emit an error. + if (II.isPoisoned() && CurLexer) { + if (&II != Ident__VA_ARGS__) // We warn about __VA_ARGS__ with poisoning. + Diag(Identifier, diag::err_pp_used_poisoned_id); + else + Diag(Identifier, diag::ext_pp_bad_vaargs_use); + } + + // If this is a macro to be expanded, do it. + if (MacroInfo *MI = getMacroInfo(&II)) { + if (!DisableMacroExpansion && !Identifier.isExpandDisabled()) { + if (MI->isEnabled()) { + if (!HandleMacroExpandedIdentifier(Identifier, MI)) + return; + } else { + // C99 6.10.3.4p2 says that a disabled macro may never again be + // expanded, even if it's in a context where it could be expanded in the + // future. + Identifier.setFlag(Token::DisableExpand); + } + } + } + + // C++ 2.11p2: If this is an alternative representation of a C++ operator, + // then we act as if it is the actual operator and not the textual + // representation of it. + if (II.isCPlusPlusOperatorKeyword()) + Identifier.setIdentifierInfo(0); + + // Change the kind of this identifier to the appropriate token kind, e.g. + // turning "for" into a keyword. + Identifier.setKind(II.getTokenID()); + + // If this is an extension token, diagnose its use. + // FIXME: tried (unsuccesfully) to shut this up when compiling with gnu99 + // For now, I'm just commenting it out (while I work on attributes). + if (II.isExtensionToken() && Features.C99) + Diag(Identifier, diag::ext_token_used); +} + diff --git a/clang/lib/Lex/ScratchBuffer.cpp b/clang/lib/Lex/ScratchBuffer.cpp new file mode 100644 index 00000000000..99fbdf75654 --- /dev/null +++ b/clang/lib/Lex/ScratchBuffer.cpp @@ -0,0 +1,72 @@ +//===--- ScratchBuffer.cpp - Scratch space for forming tokens -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ScratchBuffer interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/ScratchBuffer.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include +using namespace clang; + +// ScratchBufSize - The size of each chunk of scratch memory. Slightly less +//than a page, almost certainly enough for anything. :) +static const unsigned ScratchBufSize = 4060; + +ScratchBuffer::ScratchBuffer(SourceManager &SM) : SourceMgr(SM), CurBuffer(0) { + // Set BytesUsed so that the first call to getToken will require an alloc. + BytesUsed = ScratchBufSize; + FileID = 0; +} + +/// getToken - Splat the specified text into a temporary MemoryBuffer and +/// return a SourceLocation that refers to the token. This is just like the +/// method below, but returns a location that indicates the physloc of the +/// token. +SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len) { + if (BytesUsed+Len > ScratchBufSize) + AllocScratchBuffer(Len); + + // Copy the token data into the buffer. + memcpy(CurBuffer+BytesUsed, Buf, Len); + + // Remember that we used these bytes. + BytesUsed += Len; + + assert(BytesUsed-Len < (1 << SourceLocation::FilePosBits) && + "Out of range file position!"); + + return SourceLocation::getFileLoc(FileID, BytesUsed-Len); +} + + +/// getToken - Splat the specified text into a temporary MemoryBuffer and +/// return a SourceLocation that refers to the token. The SourceLoc value +/// gives a virtual location that the token will appear to be from. +SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len, + SourceLocation SourceLoc) { + // Map the physloc to the specified sourceloc. + return SourceMgr.getInstantiationLoc(getToken(Buf, Len), SourceLoc); +} + +void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) { + // Only pay attention to the requested length if it is larger than our default + // page size. If it is, we allocate an entire chunk for it. This is to + // support gigantic tokens, which almost certainly won't happen. :) + if (RequestLen < ScratchBufSize) + RequestLen = ScratchBufSize; + + llvm::MemoryBuffer *Buf = + llvm::MemoryBuffer::getNewMemBuffer(RequestLen, ""); + FileID = SourceMgr.createFileIDForMemBuffer(Buf); + CurBuffer = const_cast(Buf->getBufferStart()); + BytesUsed = 0; +} diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp new file mode 100644 index 00000000000..fc8cfd715c4 --- /dev/null +++ b/clang/lib/Lex/TokenLexer.cpp @@ -0,0 +1,488 @@ +//===--- TokenLexer.cpp - Lex from a token stream -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TokenLexer interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/TokenLexer.h" +#include "MacroArgs.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallVector.h" +using namespace clang; + + +/// Create a TokenLexer for the specified macro with the specified actual +/// arguments. Note that this ctor takes ownership of the ActualArgs pointer. +void TokenLexer::Init(Token &Tok, MacroArgs *Actuals) { + // If the client is reusing a TokenLexer, make sure to free any memory + // associated with it. + destroy(); + + Macro = PP.getMacroInfo(Tok.getIdentifierInfo()); + ActualArgs = Actuals; + CurToken = 0; + InstantiateLoc = Tok.getLocation(); + AtStartOfLine = Tok.isAtStartOfLine(); + HasLeadingSpace = Tok.hasLeadingSpace(); + Tokens = &*Macro->tokens_begin(); + OwnsTokens = false; + DisableMacroExpansion = false; + NumTokens = Macro->tokens_end()-Macro->tokens_begin(); + + // If this is a function-like macro, expand the arguments and change + // Tokens to point to the expanded tokens. + if (Macro->isFunctionLike() && Macro->getNumArgs()) + ExpandFunctionArguments(); + + // Mark the macro as currently disabled, so that it is not recursively + // expanded. The macro must be disabled only after argument pre-expansion of + // function-like macro arguments occurs. + Macro->DisableMacro(); +} + + + +/// Create a TokenLexer for the specified token stream. This does not +/// take ownership of the specified token vector. +void TokenLexer::Init(const Token *TokArray, unsigned NumToks, + bool disableMacroExpansion, bool ownsTokens) { + // If the client is reusing a TokenLexer, make sure to free any memory + // associated with it. + destroy(); + + Macro = 0; + ActualArgs = 0; + Tokens = TokArray; + OwnsTokens = ownsTokens; + DisableMacroExpansion = disableMacroExpansion; + NumTokens = NumToks; + CurToken = 0; + InstantiateLoc = SourceLocation(); + AtStartOfLine = false; + HasLeadingSpace = false; + + // Set HasLeadingSpace/AtStartOfLine so that the first token will be + // returned unmodified. + if (NumToks != 0) { + AtStartOfLine = TokArray[0].isAtStartOfLine(); + HasLeadingSpace = TokArray[0].hasLeadingSpace(); + } +} + + +void TokenLexer::destroy() { + // If this was a function-like macro that actually uses its arguments, delete + // the expanded tokens. + if (OwnsTokens) { + delete [] Tokens; + Tokens = 0; + } + + // TokenLexer owns its formal arguments. + if (ActualArgs) ActualArgs->destroy(); +} + +/// Expand the arguments of a function-like macro so that we can quickly +/// return preexpanded tokens from Tokens. +void TokenLexer::ExpandFunctionArguments() { + llvm::SmallVector ResultToks; + + // Loop through 'Tokens', expanding them into ResultToks. Keep + // track of whether we change anything. If not, no need to keep them. If so, + // we install the newly expanded sequence as the new 'Tokens' list. + bool MadeChange = false; + + // NextTokGetsSpace - When this is true, the next token appended to the + // output list will get a leading space, regardless of whether it had one to + // begin with or not. This is used for placemarker support. + bool NextTokGetsSpace = false; + + for (unsigned i = 0, e = NumTokens; i != e; ++i) { + // If we found the stringify operator, get the argument stringified. The + // preprocessor already verified that the following token is a macro name + // when the #define was parsed. + const Token &CurTok = Tokens[i]; + if (CurTok.is(tok::hash) || CurTok.is(tok::hashat)) { + int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo()); + assert(ArgNo != -1 && "Token following # is not an argument?"); + + Token Res; + if (CurTok.is(tok::hash)) // Stringify + Res = ActualArgs->getStringifiedArgument(ArgNo, PP); + else { + // 'charify': don't bother caching these. + Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo), + PP, true); + } + + // The stringified/charified string leading space flag gets set to match + // the #/#@ operator. + if (CurTok.hasLeadingSpace() || NextTokGetsSpace) + Res.setFlag(Token::LeadingSpace); + + ResultToks.push_back(Res); + MadeChange = true; + ++i; // Skip arg name. + NextTokGetsSpace = false; + continue; + } + + // Otherwise, if this is not an argument token, just add the token to the + // output buffer. + IdentifierInfo *II = CurTok.getIdentifierInfo(); + int ArgNo = II ? Macro->getArgumentNum(II) : -1; + if (ArgNo == -1) { + // This isn't an argument, just add it. + ResultToks.push_back(CurTok); + + if (NextTokGetsSpace) { + ResultToks.back().setFlag(Token::LeadingSpace); + NextTokGetsSpace = false; + } + continue; + } + + // An argument is expanded somehow, the result is different than the + // input. + MadeChange = true; + + // Otherwise, this is a use of the argument. Find out if there is a paste + // (##) operator before or after the argument. + bool PasteBefore = + !ResultToks.empty() && ResultToks.back().is(tok::hashhash); + bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash); + + // If it is not the LHS/RHS of a ## operator, we must pre-expand the + // argument and substitute the expanded tokens into the result. This is + // C99 6.10.3.1p1. + if (!PasteBefore && !PasteAfter) { + const Token *ResultArgToks; + + // Only preexpand the argument if it could possibly need it. This + // avoids some work in common cases. + const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo); + if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP)) + ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0]; + else + ResultArgToks = ArgTok; // Use non-preexpanded tokens. + + // If the arg token expanded into anything, append it. + if (ResultArgToks->isNot(tok::eof)) { + unsigned FirstResult = ResultToks.size(); + unsigned NumToks = MacroArgs::getArgLength(ResultArgToks); + ResultToks.append(ResultArgToks, ResultArgToks+NumToks); + + // If any tokens were substituted from the argument, the whitespace + // before the first token should match the whitespace of the arg + // identifier. + ResultToks[FirstResult].setFlagValue(Token::LeadingSpace, + CurTok.hasLeadingSpace() || + NextTokGetsSpace); + NextTokGetsSpace = false; + } else { + // If this is an empty argument, and if there was whitespace before the + // formal token, make sure the next token gets whitespace before it. + NextTokGetsSpace = CurTok.hasLeadingSpace(); + } + continue; + } + + // Okay, we have a token that is either the LHS or RHS of a paste (##) + // argument. It gets substituted as its non-pre-expanded tokens. + const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo); + unsigned NumToks = MacroArgs::getArgLength(ArgToks); + if (NumToks) { // Not an empty argument? + // If this is the GNU ", ## __VA_ARG__" extension, and we just learned + // that __VA_ARG__ expands to multiple tokens, avoid a pasting error when + // the expander trys to paste ',' with the first token of the __VA_ARG__ + // expansion. + if (PasteBefore && ResultToks.size() >= 2 && + ResultToks[ResultToks.size()-2].is(tok::comma) && + (unsigned)ArgNo == Macro->getNumArgs()-1 && + Macro->isVariadic()) { + // Remove the paste operator, report use of the extension. + PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); + ResultToks.pop_back(); + } + + ResultToks.append(ArgToks, ArgToks+NumToks); + + // If the next token was supposed to get leading whitespace, ensure it has + // it now. + if (NextTokGetsSpace) { + ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace); + NextTokGetsSpace = false; + } + continue; + } + + // If an empty argument is on the LHS or RHS of a paste, the standard (C99 + // 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We + // implement this by eating ## operators when a LHS or RHS expands to + // empty. + NextTokGetsSpace |= CurTok.hasLeadingSpace(); + if (PasteAfter) { + // Discard the argument token and skip (don't copy to the expansion + // buffer) the paste operator after it. + NextTokGetsSpace |= Tokens[i+1].hasLeadingSpace(); + ++i; + continue; + } + + // If this is on the RHS of a paste operator, we've already copied the + // paste operator to the ResultToks list. Remove it. + assert(PasteBefore && ResultToks.back().is(tok::hashhash)); + NextTokGetsSpace |= ResultToks.back().hasLeadingSpace(); + ResultToks.pop_back(); + + // If this is the __VA_ARGS__ token, and if the argument wasn't provided, + // and if the macro had at least one real argument, and if the token before + // the ## was a comma, remove the comma. + if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__ + ActualArgs->isVarargsElidedUse() && // Argument elided. + !ResultToks.empty() && ResultToks.back().is(tok::comma)) { + // Never add a space, even if the comma, ##, or arg had a space. + NextTokGetsSpace = false; + // Remove the paste operator, report use of the extension. + PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); + ResultToks.pop_back(); + } + continue; + } + + // If anything changed, install this as the new Tokens list. + if (MadeChange) { + // This is deleted in the dtor. + NumTokens = ResultToks.size(); + Token *Res = new Token[ResultToks.size()]; + if (NumTokens) + memcpy(Res, &ResultToks[0], NumTokens*sizeof(Token)); + Tokens = Res; + OwnsTokens = true; + } +} + +/// Lex - Lex and return a token from this macro stream. +/// +void TokenLexer::Lex(Token &Tok) { + // Lexing off the end of the macro, pop this macro off the expansion stack. + if (isAtEnd()) { + // If this is a macro (not a token stream), mark the macro enabled now + // that it is no longer being expanded. + if (Macro) Macro->EnableMacro(); + + // Pop this context off the preprocessors lexer stack and get the next + // token. This will delete "this" so remember the PP instance var. + Preprocessor &PPCache = PP; + if (PP.HandleEndOfTokenLexer(Tok)) + return; + + // HandleEndOfTokenLexer may not return a token. If it doesn't, lex + // whatever is next. + return PPCache.Lex(Tok); + } + + // If this is the first token of the expanded result, we inherit spacing + // properties later. + bool isFirstToken = CurToken == 0; + + // Get the next token to return. + Tok = Tokens[CurToken++]; + + // If this token is followed by a token paste (##) operator, paste the tokens! + if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) + if (PasteTokens(Tok)) { + // When handling the microsoft /##/ extension, the final token is + // returned by PasteTokens, not the pasted token. + return; + } + + // The token's current location indicate where the token was lexed from. We + // need this information to compute the spelling of the token, but any + // diagnostics for the expanded token should appear as if they came from + // InstantiationLoc. Pull this information together into a new SourceLocation + // that captures all of this. + if (InstantiateLoc.isValid()) { // Don't do this for token streams. + SourceManager &SrcMgr = PP.getSourceManager(); + Tok.setLocation(SrcMgr.getInstantiationLoc(Tok.getLocation(), + InstantiateLoc)); + } + + // If this is the first token, set the lexical properties of the token to + // match the lexical properties of the macro identifier. + if (isFirstToken) { + Tok.setFlagValue(Token::StartOfLine , AtStartOfLine); + Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); + } + + // Handle recursive expansion! + if (Tok.getIdentifierInfo() && !DisableMacroExpansion) + return PP.HandleIdentifier(Tok); + + // Otherwise, return a normal token. +} + +/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## +/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there +/// are is another ## after it, chomp it iteratively. Return the result as Tok. +/// If this returns true, the caller should immediately return the token. +bool TokenLexer::PasteTokens(Token &Tok) { + llvm::SmallVector Buffer; + do { + // Consume the ## operator. + SourceLocation PasteOpLoc = Tokens[CurToken].getLocation(); + ++CurToken; + assert(!isAtEnd() && "No token on the RHS of a paste operator!"); + + // Get the RHS token. + const Token &RHS = Tokens[CurToken]; + + bool isInvalid = false; + + // Allocate space for the result token. This is guaranteed to be enough for + // the two tokens and a null terminator. + Buffer.resize(Tok.getLength() + RHS.getLength() + 1); + + // Get the spelling of the LHS token in Buffer. + const char *BufPtr = &Buffer[0]; + unsigned LHSLen = PP.getSpelling(Tok, BufPtr); + if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer! + memcpy(&Buffer[0], BufPtr, LHSLen); + + BufPtr = &Buffer[LHSLen]; + unsigned RHSLen = PP.getSpelling(RHS, BufPtr); + if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer! + memcpy(&Buffer[LHSLen], BufPtr, RHSLen); + + // Add null terminator. + Buffer[LHSLen+RHSLen] = '\0'; + + // Trim excess space. + Buffer.resize(LHSLen+RHSLen+1); + + // Plop the pasted result (including the trailing newline and null) into a + // scratch buffer where we can lex it. + SourceLocation ResultTokLoc = PP.CreateString(&Buffer[0], Buffer.size()); + + // Lex the resultant pasted token into Result. + Token Result; + + // Avoid testing /*, as the lexer would think it is the start of a comment + // and emit an error that it is unterminated. + if (Tok.is(tok::slash) && RHS.is(tok::star)) { + isInvalid = true; + } else if (Tok.is(tok::identifier) && RHS.is(tok::identifier)) { + // Common paste case: identifier+identifier = identifier. Avoid creating + // a lexer and other overhead. + PP.IncrementPasteCounter(true); + Result.startToken(); + Result.setKind(tok::identifier); + Result.setLocation(ResultTokLoc); + Result.setLength(LHSLen+RHSLen); + } else { + PP.IncrementPasteCounter(false); + + // Make a lexer to lex this string from. + SourceManager &SourceMgr = PP.getSourceManager(); + const char *ResultStrData = SourceMgr.getCharacterData(ResultTokLoc); + + // Make a lexer object so that we lex and expand the paste result. + Lexer *TL = new Lexer(ResultTokLoc, PP, ResultStrData, + ResultStrData+LHSLen+RHSLen /*don't include null*/); + + // Lex a token in raw mode. This way it won't look up identifiers + // automatically, lexing off the end will return an eof token, and + // warnings are disabled. This returns true if the result token is the + // entire buffer. + bool IsComplete = TL->LexRawToken(Result); + + // If we got an EOF token, we didn't form even ONE token. For example, we + // did "/ ## /" to get "//". + IsComplete &= Result.isNot(tok::eof); + isInvalid = !IsComplete; + + // We're now done with the temporary lexer. + delete TL; + } + + // If pasting the two tokens didn't form a full new token, this is an error. + // This occurs with "x ## +" and other stuff. Return with Tok unmodified + // and with RHS as the next token to lex. + if (isInvalid) { + // Test for the Microsoft extension of /##/ turning into // here on the + // error path. + if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) && + RHS.is(tok::slash)) { + HandleMicrosoftCommentPaste(Tok); + return true; + } else { + // TODO: If not in assembler language mode. + PP.Diag(PasteOpLoc, diag::err_pp_bad_paste, + std::string(Buffer.begin(), Buffer.end()-1)); + return false; + } + } + + // Turn ## into 'unknown' to avoid # ## # from looking like a paste + // operator. + if (Result.is(tok::hashhash)) + Result.setKind(tok::unknown); + // FIXME: Turn __VA_ARGS__ into "not a token"? + + // Transfer properties of the LHS over the the Result. + Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine()); + Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace()); + + // Finally, replace LHS with the result, consume the RHS, and iterate. + ++CurToken; + Tok = Result; + } while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)); + + // Now that we got the result token, it will be subject to expansion. Since + // token pasting re-lexes the result token in raw mode, identifier information + // isn't looked up. As such, if the result is an identifier, look up id info. + if (Tok.is(tok::identifier)) { + // Look up the identifier info for the token. We disabled identifier lookup + // by saying we're skipping contents, so we need to do this manually. + Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok)); + } + return false; +} + +/// isNextTokenLParen - If the next token lexed will pop this macro off the +/// expansion stack, return 2. If the next unexpanded token is a '(', return +/// 1, otherwise return 0. +unsigned TokenLexer::isNextTokenLParen() const { + // Out of tokens? + if (isAtEnd()) + return 2; + return Tokens[CurToken].is(tok::l_paren); +} + + +/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes +/// together to form a comment that comments out everything in the current +/// macro, other active macros, and anything left on the current physical +/// source line of the instantiated buffer. Handle this by returning the +/// first token on the next line. +void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) { + // We 'comment out' the rest of this macro by just ignoring the rest of the + // tokens that have not been lexed yet, if any. + + // Since this must be a macro, mark the macro enabled now that it is no longer + // being expanded. + assert(Macro && "Token streams can't paste comments"); + Macro->EnableMacro(); + + PP.HandleMicrosoftCommentPaste(Tok); +} diff --git a/clang/lib/Makefile b/clang/lib/Makefile new file mode 100755 index 00000000000..f6514d57c77 --- /dev/null +++ b/clang/lib/Makefile @@ -0,0 +1,14 @@ +##===- lib/Makefile ----------------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../.. + +PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Parse/AttributeList.cpp b/clang/lib/Parse/AttributeList.cpp new file mode 100644 index 00000000000..0ff9447d2e6 --- /dev/null +++ b/clang/lib/Parse/AttributeList.cpp @@ -0,0 +1,98 @@ +//===--- AttributeList.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AttributeList class implementation +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/AttributeList.h" +using namespace clang; + +AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, + IdentifierInfo *pName, SourceLocation pLoc, + Action::ExprTy **elist, unsigned numargs, + AttributeList *n) + : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc), + NumArgs(numargs), Next(n) { + Args = new Action::ExprTy*[numargs]; + for (unsigned i = 0; i != numargs; ++i) + Args[i] = elist[i]; +} + +AttributeList::~AttributeList() { + if (Args) { + // FIXME: before we delete the vector, we need to make sure the Expr's + // have been deleted. Since Action::ExprTy is "void", we are dependent + // on the actions module for actually freeing the memory. The specific + // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType, + // ParseField, ParseTag. Once these routines have freed the expression, + // they should zero out the Args slot (to indicate the memory has been + // freed). If any element of the vector is non-null, we should assert. + delete [] Args; + } + delete Next; +} + +AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { + const char *Str = Name->getName(); + unsigned Len = Name->getLength(); + + // Normalize the attribute name, __foo__ becomes foo. + if (Len > 4 && Str[0] == '_' && Str[1] == '_' && + Str[Len - 2] == '_' && Str[Len - 1] == '_') { + Str += 2; + Len -= 4; + } + + switch (Len) { + case 4: + if (!memcmp(Str, "weak", 4)) return AT_weak; + if (!memcmp(Str, "pure", 4)) return AT_pure; + break; + case 6: + if (!memcmp(Str, "packed", 6)) return AT_packed; + if (!memcmp(Str, "malloc", 6)) return AT_malloc; + if (!memcmp(Str, "format", 6)) return AT_format; + if (!memcmp(Str, "unused", 6)) return AT_unused; + break; + case 7: + if (!memcmp(Str, "aligned", 7)) return AT_aligned; + if (!memcmp(Str, "nothrow", 7)) return AT_nothrow; + if (!memcmp(Str, "nonnull", 7)) return AT_nonnull; + if (!memcmp(Str, "stdcall", 7)) return AT_stdcall; + break; + case 8: + if (!memcmp(Str, "annotate", 8)) return AT_annotate; + if (!memcmp(Str, "noreturn", 8)) return AT_noreturn; + if (!memcmp(Str, "noinline", 8)) return AT_noinline; + if (!memcmp(Str, "fastcall", 8)) return AT_fastcall; + break; + case 9: + if (!memcmp(Str, "dllimport", 9)) return AT_dllimport; + if (!memcmp(Str, "dllexport", 9)) return AT_dllexport; + break; + case 10: + if (!memcmp(Str, "deprecated", 10)) return AT_deprecated; + if (!memcmp(Str, "visibility", 10)) return AT_visibility; + break; + case 11: + if (!memcmp(Str, "vector_size", 11)) return AT_vector_size; + break; + case 13: + if (!memcmp(Str, "address_space", 13)) return AT_address_space; + break; + case 15: + if (!memcmp(Str, "ocu_vector_type", 15)) return AT_ocu_vector_type; + break; + case 18: + if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result; + break; + } + return UnknownAttribute; +} diff --git a/clang/lib/Parse/DeclSpec.cpp b/clang/lib/Parse/DeclSpec.cpp new file mode 100644 index 00000000000..1cd350893f4 --- /dev/null +++ b/clang/lib/Parse/DeclSpec.cpp @@ -0,0 +1,287 @@ +//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for declaration specifiers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +using namespace clang; + +/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this +/// +unsigned DeclSpec::getParsedSpecifiers() const { + unsigned Res = 0; + if (StorageClassSpec != SCS_unspecified || + SCS_thread_specified) + Res |= PQ_StorageClassSpecifier; + + if (TypeQualifiers != TQ_unspecified) + Res |= PQ_TypeQualifier; + + if (hasTypeSpecifier()) + Res |= PQ_TypeSpecifier; + + if (FS_inline_specified) + Res |= PQ_FunctionSpecifier; + return Res; +} + +const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { + switch (S) { + default: assert(0 && "Unknown typespec!"); + case DeclSpec::SCS_unspecified: return "unspecified"; + case DeclSpec::SCS_typedef: return "typedef"; + case DeclSpec::SCS_extern: return "extern"; + case DeclSpec::SCS_static: return "static"; + case DeclSpec::SCS_auto: return "auto"; + case DeclSpec::SCS_register: return "register"; + } +} + +bool DeclSpec::BadSpecifier(SCS S, const char *&PrevSpec) { + PrevSpec = getSpecifierName(S); + return true; +} + +bool DeclSpec::BadSpecifier(TSW W, const char *&PrevSpec) { + switch (W) { + case TSW_unspecified: PrevSpec = "unspecified"; break; + case TSW_short: PrevSpec = "short"; break; + case TSW_long: PrevSpec = "long"; break; + case TSW_longlong: PrevSpec = "long long"; break; + } + return true; +} + +bool DeclSpec::BadSpecifier(TSC C, const char *&PrevSpec) { + switch (C) { + case TSC_unspecified: PrevSpec = "unspecified"; break; + case TSC_imaginary: PrevSpec = "imaginary"; break; + case TSC_complex: PrevSpec = "complex"; break; + } + return true; +} + + +bool DeclSpec::BadSpecifier(TSS S, const char *&PrevSpec) { + switch (S) { + case TSS_unspecified: PrevSpec = "unspecified"; break; + case TSS_signed: PrevSpec = "signed"; break; + case TSS_unsigned: PrevSpec = "unsigned"; break; + } + return true; +} + +const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { + switch (T) { + default: assert(0 && "Unknown typespec!"); + case DeclSpec::TST_unspecified: return "unspecified"; + case DeclSpec::TST_void: return "void"; + case DeclSpec::TST_char: return "char"; + case DeclSpec::TST_int: return "int"; + case DeclSpec::TST_float: return "float"; + case DeclSpec::TST_double: return "double"; + case DeclSpec::TST_bool: return "_Bool"; + case DeclSpec::TST_decimal32: return "_Decimal32"; + case DeclSpec::TST_decimal64: return "_Decimal64"; + case DeclSpec::TST_decimal128: return "_Decimal128"; + case DeclSpec::TST_enum: return "enum"; + case DeclSpec::TST_union: return "union"; + case DeclSpec::TST_struct: return "struct"; + case DeclSpec::TST_typedef: return "typedef"; + case DeclSpec::TST_typeofType: + case DeclSpec::TST_typeofExpr: return "typeof"; + } +} + +bool DeclSpec::BadSpecifier(TST T, const char *&PrevSpec) { + PrevSpec = getSpecifierName(T); + return true; +} + +bool DeclSpec::BadSpecifier(TQ T, const char *&PrevSpec) { + switch (T) { + case DeclSpec::TQ_unspecified: PrevSpec = "unspecified"; break; + case DeclSpec::TQ_const: PrevSpec = "const"; break; + case DeclSpec::TQ_restrict: PrevSpec = "restrict"; break; + case DeclSpec::TQ_volatile: PrevSpec = "volatile"; break; + } + return true; +} + +bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, + const char *&PrevSpec) { + if (StorageClassSpec != SCS_unspecified) + return BadSpecifier( (SCS)StorageClassSpec, PrevSpec); + StorageClassSpec = S; + StorageClassSpecLoc = Loc; + return false; +} + +bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, + const char *&PrevSpec) { + if (SCS_thread_specified) { + PrevSpec = "__thread"; + return true; + } + SCS_thread_specified = true; + SCS_threadLoc = Loc; + return false; +} + + +/// These methods set the specified attribute of the DeclSpec, but return true +/// and ignore the request if invalid (e.g. "extern" then "auto" is +/// specified). +bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, + const char *&PrevSpec) { + if (TypeSpecWidth != TSW_unspecified && + // Allow turning long -> long long. + (W != TSW_longlong || TypeSpecWidth != TSW_long)) + return BadSpecifier( (TSW)TypeSpecWidth, PrevSpec); + TypeSpecWidth = W; + TSWLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, + const char *&PrevSpec) { + if (TypeSpecComplex != TSC_unspecified) + return BadSpecifier( (TSC)TypeSpecComplex, PrevSpec); + TypeSpecComplex = C; + TSCLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, + const char *&PrevSpec) { + if (TypeSpecSign != TSS_unspecified) + return BadSpecifier( (TSS)TypeSpecSign, PrevSpec); + TypeSpecSign = S; + TSSLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, void *Rep) { + if (TypeSpecType != TST_unspecified) + return BadSpecifier( (TST)TypeSpecType, PrevSpec); + TypeSpecType = T; + TypeRep = Rep; + TSTLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + const LangOptions &Lang) { + // Duplicates turn into warnings pre-C99. + if ((TypeQualifiers & T) && !Lang.C99) + return BadSpecifier(T, PrevSpec); + TypeQualifiers |= T; + + switch (T) { + default: assert(0 && "Unknown type qualifier!"); + case TQ_const: TQ_constLoc = Loc; break; + case TQ_restrict: TQ_restrictLoc = Loc; break; + case TQ_volatile: TQ_volatileLoc = Loc; break; + } + return false; +} + +bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){ + // 'inline inline' is ok. + FS_inline_specified = true; + FS_inlineLoc = Loc; + return false; +} + + +/// Finish - This does final analysis of the declspec, rejecting things like +/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or +/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, +/// DeclSpec is guaranteed self-consistent, even if an error occurred. +void DeclSpec::Finish(Diagnostic &D, SourceManager& SrcMgr, + const LangOptions &Lang) { + // Check the type specifier components first. + + // signed/unsigned are only valid with int/char. + if (TypeSpecSign != TSS_unspecified) { + if (TypeSpecType == TST_unspecified) + TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. + else if (TypeSpecType != TST_int && TypeSpecType != TST_char) { + Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec, + getSpecifierName( (TST)TypeSpecType)); + // signed double -> double. + TypeSpecSign = TSS_unspecified; + } + } + + // Validate the width of the type. + switch (TypeSpecWidth) { + case TSW_unspecified: break; + case TSW_short: // short int + case TSW_longlong: // long long int + if (TypeSpecType == TST_unspecified) + TypeSpecType = TST_int; // short -> short int, long long -> long long int. + else if (TypeSpecType != TST_int) { + Diag(D, TSWLoc, SrcMgr, + TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec + : diag::err_invalid_longlong_spec, + getSpecifierName( (TST)TypeSpecType)); + TypeSpecType = TST_int; + } + break; + case TSW_long: // long double, long int + if (TypeSpecType == TST_unspecified) + TypeSpecType = TST_int; // long -> long int. + else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { + Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec, + getSpecifierName( (TST)TypeSpecType)); + TypeSpecType = TST_int; + } + break; + } + + // TODO: if the implementation does not implement _Complex or _Imaginary, + // disallow their use. Need information about the backend. + if (TypeSpecComplex != TSC_unspecified) { + if (TypeSpecType == TST_unspecified) { + Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex); + TypeSpecType = TST_double; // _Complex -> _Complex double. + } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { + // Note that this intentionally doesn't include _Complex _Bool. + Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); + } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { + Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec, + getSpecifierName( (TST)TypeSpecType)); + TypeSpecComplex = TSC_unspecified; + } + } + + // Verify __thread. + if (SCS_thread_specified) { + if (StorageClassSpec == SCS_unspecified) { + StorageClassSpec = SCS_extern; // '__thread int' -> 'extern __thread int' + } else if (StorageClassSpec != SCS_extern && + StorageClassSpec != SCS_static) { + Diag(D, getStorageClassSpecLoc(), SrcMgr, diag::err_invalid_thread_spec, + getSpecifierName( (SCS)StorageClassSpec)); + SCS_thread_specified = false; + } + } + + // Okay, now we can infer the real type. + + // TODO: return "auto function" and other bad things based on the real type. + + // 'data definition has no type or storage class'? +} diff --git a/clang/lib/Parse/Makefile b/clang/lib/Parse/Makefile new file mode 100644 index 00000000000..b5d2653bb09 --- /dev/null +++ b/clang/lib/Parse/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/Parse/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Parser library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangParse +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Parse/MinimalAction.cpp b/clang/lib/Parse/MinimalAction.cpp new file mode 100644 index 00000000000..250fa76ccc4 --- /dev/null +++ b/clang/lib/Parse/MinimalAction.cpp @@ -0,0 +1,136 @@ +//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MinimalAction interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +using namespace clang; + +/// TypeNameInfo - A link exists here for each scope that an identifier is +/// defined. +struct TypeNameInfo { + TypeNameInfo *Prev; + bool isTypeName; + + TypeNameInfo(bool istypename, TypeNameInfo *prev) { + isTypeName = istypename; + Prev = prev; + } +}; + +void MinimalAction:: ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { + TUScope = S; + IdentifierInfo *II; + TypeNameInfo *TI; + + // recognize the ObjC built-in type identifiers. + II = &Idents.get("id"); + TI = new TypeNameInfo(1, II->getFETokenInfo()); + II->setFETokenInfo(TI); + II = &Idents.get("SEL"); + TI = new TypeNameInfo(1, II->getFETokenInfo()); + II->setFETokenInfo(TI); + II = &Idents.get("Class"); + TI = new TypeNameInfo(1, II->getFETokenInfo()); + II->setFETokenInfo(TI); + II = &Idents.get("Protocol"); + TI = new TypeNameInfo(1, II->getFETokenInfo()); + II->setFETokenInfo(TI); +} + +/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to +/// determine whether the name is a type name (objc class name or typedef) or +/// not in this scope. +Action::DeclTy * +MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) const { + if (TypeNameInfo *TI = II.getFETokenInfo()) + if (TI->isTypeName) + return TI; + return 0; +} + +/// ActOnDeclarator - If this is a typedef declarator, we modify the +/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is +/// popped. +Action::DeclTy * +MinimalAction::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup) { + IdentifierInfo *II = D.getIdentifier(); + + // If there is no identifier associated with this declarator, bail out. + if (II == 0) return 0; + + TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo(); + bool isTypeName = + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef; + + // this check avoids creating TypeNameInfo objects for the common case. + // It does need to handle the uncommon case of shadowing a typedef name with a + // non-typedef name. e.g. { typedef int a; a xx; { int a; } } + if (weCurrentlyHaveTypeInfo || isTypeName) { + TypeNameInfo *TI = new TypeNameInfo(isTypeName, weCurrentlyHaveTypeInfo); + + II->setFETokenInfo(TI); + + // Remember that this needs to be removed when the scope is popped. + S->AddDecl(II); + } + return 0; +} + +Action::DeclTy * +MinimalAction::ActOnStartClassInterface(SourceLocation AtInterafceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + IdentifierInfo **ProtocolNames, unsigned NumProtocols, + SourceLocation EndProtoLoc, AttributeList *AttrList) { + TypeNameInfo *TI = + new TypeNameInfo(1, ClassName->getFETokenInfo()); + + ClassName->setFETokenInfo(TI); + return 0; +} + +/// ActOnForwardClassDeclaration - +/// Scope will always be top level file scope. +Action::DeclTy * +MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, + IdentifierInfo **IdentList, unsigned NumElts) { + for (unsigned i = 0; i != NumElts; ++i) { + TypeNameInfo *TI = + new TypeNameInfo(1, IdentList[i]->getFETokenInfo()); + + IdentList[i]->setFETokenInfo(TI); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IdentList[i]); + } + return 0; +} + +/// ActOnPopScope - When a scope is popped, if any typedefs are now out-of-scope, +/// they are removed from the IdentifierInfo::FETokenInfo field. +void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) { + for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); + I != E; ++I) { + IdentifierInfo &II = *static_cast(*I); + TypeNameInfo *TI = II.getFETokenInfo(); + assert(TI && "This decl didn't get pushed??"); + + if (TI) { + TypeNameInfo *Next = TI->Prev; + delete TI; + + II.setFETokenInfo(Next); + } + } +} diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp new file mode 100644 index 00000000000..7d15e984ee6 --- /dev/null +++ b/clang/lib/Parse/ParseDecl.cpp @@ -0,0 +1,1540 @@ +//===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Declaration portions of the Parser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +#include "llvm/ADT/SmallSet.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// C99 6.7: Declarations. +//===----------------------------------------------------------------------===// + +/// ParseTypeName +/// type-name: [C99 6.7.6] +/// specifier-qualifier-list abstract-declarator[opt] +Parser::TypeTy *Parser::ParseTypeName() { + // Parse the common declaration-specifiers piece. + DeclSpec DS; + ParseSpecifierQualifierList(DS); + + // Parse the abstract-declarator, if present. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); + + return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; +} + +/// ParseAttributes - Parse a non-empty attributes list. +/// +/// [GNU] attributes: +/// attribute +/// attributes attribute +/// +/// [GNU] attribute: +/// '__attribute__' '(' '(' attribute-list ')' ')' +/// +/// [GNU] attribute-list: +/// attrib +/// attribute_list ',' attrib +/// +/// [GNU] attrib: +/// empty +/// attrib-name +/// attrib-name '(' identifier ')' +/// attrib-name '(' identifier ',' nonempty-expr-list ')' +/// attrib-name '(' argument-expression-list [C99 6.5.2] ')' +/// +/// [GNU] attrib-name: +/// identifier +/// typespec +/// typequal +/// storageclass +/// +/// FIXME: The GCC grammar/code for this construct implies we need two +/// token lookahead. Comment from gcc: "If they start with an identifier +/// which is followed by a comma or close parenthesis, then the arguments +/// start with that identifier; otherwise they are an expression list." +/// +/// At the moment, I am not doing 2 token lookahead. I am also unaware of +/// any attributes that don't work (based on my limited testing). Most +/// attributes are very simple in practice. Until we find a bug, I don't see +/// a pressing need to implement the 2 token lookahead. + +AttributeList *Parser::ParseAttributes() { + assert(Tok.is(tok::kw___attribute) && "Not an attribute list!"); + + AttributeList *CurrAttr = 0; + + while (Tok.is(tok::kw___attribute)) { + ConsumeToken(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "attribute")) { + SkipUntil(tok::r_paren, true); // skip until ) or ; + return CurrAttr; + } + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { + SkipUntil(tok::r_paren, true); // skip until ) or ; + return CurrAttr; + } + // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) + while (Tok.is(tok::identifier) || isDeclarationSpecifier() || + Tok.is(tok::comma)) { + + if (Tok.is(tok::comma)) { + // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) + ConsumeToken(); + continue; + } + // we have an identifier or declaration specifier (const, int, etc.) + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + + // check if we have a "paramterized" attribute + if (Tok.is(tok::l_paren)) { + ConsumeParen(); // ignore the left paren loc for now + + if (Tok.is(tok::identifier)) { + IdentifierInfo *ParmName = Tok.getIdentifierInfo(); + SourceLocation ParmLoc = ConsumeToken(); + + if (Tok.is(tok::r_paren)) { + // __attribute__(( mode(byte) )) + ConsumeParen(); // ignore the right paren loc for now + CurrAttr = new AttributeList(AttrName, AttrNameLoc, + ParmName, ParmLoc, 0, 0, CurrAttr); + } else if (Tok.is(tok::comma)) { + ConsumeToken(); + // __attribute__(( format(printf, 1, 2) )) + llvm::SmallVector ArgExprs; + bool ArgExprsOk = true; + + // now parse the non-empty comma separated list of expressions + while (1) { + ExprResult ArgExpr = ParseAssignmentExpression(); + if (ArgExpr.isInvalid) { + ArgExprsOk = false; + SkipUntil(tok::r_paren); + break; + } else { + ArgExprs.push_back(ArgExpr.Val); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + if (ArgExprsOk && Tok.is(tok::r_paren)) { + ConsumeParen(); // ignore the right paren loc for now + CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, + ParmLoc, &ArgExprs[0], ArgExprs.size(), CurrAttr); + } + } + } else { // not an identifier + // parse a possibly empty comma separated list of expressions + if (Tok.is(tok::r_paren)) { + // __attribute__(( nonnull() )) + ConsumeParen(); // ignore the right paren loc for now + CurrAttr = new AttributeList(AttrName, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr); + } else { + // __attribute__(( aligned(16) )) + llvm::SmallVector ArgExprs; + bool ArgExprsOk = true; + + // now parse the list of expressions + while (1) { + ExprResult ArgExpr = ParseAssignmentExpression(); + if (ArgExpr.isInvalid) { + ArgExprsOk = false; + SkipUntil(tok::r_paren); + break; + } else { + ArgExprs.push_back(ArgExpr.Val); + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // Eat the comma, move to the next argument + } + // Match the ')'. + if (ArgExprsOk && Tok.is(tok::r_paren)) { + ConsumeParen(); // ignore the right paren loc for now + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + SourceLocation(), &ArgExprs[0], ArgExprs.size(), + CurrAttr); + } + } + } + } else { + CurrAttr = new AttributeList(AttrName, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr); + } + } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, false); + } + return CurrAttr; +} + +/// ParseDeclaration - Parse a full 'declaration', which consists of +/// declaration-specifiers, some number of declarators, and a semicolon. +/// 'Context' should be a Declarator::TheContext value. +/// +/// declaration: [C99 6.7] +/// block-declaration -> +/// simple-declaration +/// others [FIXME] +/// [C++] namespace-definition +/// others... [FIXME] +/// +Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) { + switch (Tok.getKind()) { + case tok::kw_namespace: + return ParseNamespace(Context); + default: + return ParseSimpleDeclaration(Context); + } +} + +/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl] +/// declaration-specifiers init-declarator-list[opt] ';' +///[C90/C++]init-declarator-list ';' [TODO] +/// [OMP] threadprivate-directive [TODO] +Parser::DeclTy *Parser::ParseSimpleDeclaration(unsigned Context) { + // Parse the common declaration-specifiers piece. + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" + // declaration-specifiers init-declarator-list[opt] ';' + if (Tok.is(tok::semi)) { + ConsumeToken(); + return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + } + + Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); + ParseDeclarator(DeclaratorInfo); + + return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); +} + + +/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after +/// parsing 'declaration-specifiers declarator'. This method is split out this +/// way to handle the ambiguity between top-level function-definitions and +/// declarations. +/// +/// init-declarator-list: [C99 6.7] +/// init-declarator +/// init-declarator-list ',' init-declarator +/// init-declarator: [C99 6.7] +/// declarator +/// declarator '=' initializer +/// [GNU] declarator simple-asm-expr[opt] attributes[opt] +/// [GNU] declarator simple-asm-expr[opt] attributes[opt] '=' initializer +/// +Parser::DeclTy *Parser:: +ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { + + // Declarators may be grouped together ("int X, *Y, Z();"). Provide info so + // that they can be chained properly if the actions want this. + Parser::DeclTy *LastDeclInGroup = 0; + + // At this point, we know that it is not a function definition. Parse the + // rest of the init-declarator-list. + while (1) { + // If a simple-asm-expr is present, parse it. + if (Tok.is(tok::kw_asm)) + ParseSimpleAsm(); + + // If attributes are present, parse them. + if (Tok.is(tok::kw___attribute)) + D.AddAttributes(ParseAttributes()); + + // Inform the current actions module that we just parsed this declarator. + // FIXME: pass asm & attributes. + LastDeclInGroup = Actions.ActOnDeclarator(CurScope, D, LastDeclInGroup); + + // Parse declarator '=' initializer. + ExprResult Init; + if (Tok.is(tok::equal)) { + ConsumeToken(); + Init = ParseInitializer(); + if (Init.isInvalid) { + SkipUntil(tok::semi); + return 0; + } + Actions.AddInitializerToDecl(LastDeclInGroup, Init.Val); + } + + // If we don't have a comma, it is either the end of the list (a ';') or an + // error, bail out. + if (Tok.isNot(tok::comma)) + break; + + // Consume the comma. + ConsumeToken(); + + // Parse the next declarator. + D.clear(); + ParseDeclarator(D); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup); + } + // If this is an ObjC2 for-each loop, this is a successful declarator + // parse. The syntax for these looks like: + // 'for' '(' declaration 'in' expr ')' statement + if (D.getContext() == Declarator::ForContext && isTokIdentifier_in()) { + return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup); + } + Diag(Tok, diag::err_parse_error); + // Skip to end of block or statement + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return 0; +} + +/// ParseSpecifierQualifierList +/// specifier-qualifier-list: +/// type-specifier specifier-qualifier-list[opt] +/// type-qualifier specifier-qualifier-list[opt] +/// [GNU] attributes specifier-qualifier-list[opt] +/// +void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { + /// specifier-qualifier-list is a subset of declaration-specifiers. Just + /// parse declaration-specifiers and complain about extra stuff. + ParseDeclarationSpecifiers(DS); + + // Validate declspec for type-name. + unsigned Specs = DS.getParsedSpecifiers(); + if (Specs == DeclSpec::PQ_None) + Diag(Tok, diag::err_typename_requires_specqual); + + // Issue diagnostic and remove storage class if present. + if (Specs & DeclSpec::PQ_StorageClassSpecifier) { + if (DS.getStorageClassSpecLoc().isValid()) + Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass); + else + Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass); + DS.ClearStorageClassSpecs(); + } + + // Issue diagnostic and remove function specfier if present. + if (Specs & DeclSpec::PQ_FunctionSpecifier) { + Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); + DS.ClearFunctionSpecs(); + } +} + +/// ParseDeclarationSpecifiers +/// declaration-specifiers: [C99 6.7] +/// storage-class-specifier declaration-specifiers[opt] +/// type-specifier declaration-specifiers[opt] +/// type-qualifier declaration-specifiers[opt] +/// [C99] function-specifier declaration-specifiers[opt] +/// [GNU] attributes declaration-specifiers[opt] +/// +/// storage-class-specifier: [C99 6.7.1] +/// 'typedef' +/// 'extern' +/// 'static' +/// 'auto' +/// 'register' +/// [GNU] '__thread' +/// type-specifier: [C99 6.7.2] +/// 'void' +/// 'char' +/// 'short' +/// 'int' +/// 'long' +/// 'float' +/// 'double' +/// 'signed' +/// 'unsigned' +/// struct-or-union-specifier +/// enum-specifier +/// typedef-name +/// [C++] 'bool' +/// [C99] '_Bool' +/// [C99] '_Complex' +/// [C99] '_Imaginary' // Removed in TC2? +/// [GNU] '_Decimal32' +/// [GNU] '_Decimal64' +/// [GNU] '_Decimal128' +/// [GNU] typeof-specifier +/// [OBJC] class-name objc-protocol-refs[opt] [TODO] +/// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] +/// type-qualifier: +/// 'const' +/// 'volatile' +/// [C99] 'restrict' +/// function-specifier: [C99 6.7.4] +/// [C99] 'inline' +/// +void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { + DS.SetRangeStart(Tok.getLocation()); + while (1) { + int isInvalid = false; + const char *PrevSpec = 0; + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + // typedef-name + case tok::identifier: + // This identifier can only be a typedef name if we haven't already seen + // a type-specifier. Without this check we misparse: + // typedef int X; struct Y { short X; }; as 'short int'. + if (!DS.hasTypeSpecifier()) { + // It has to be available as a typedef too! + if (void *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), + CurScope)) { + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, + TypeRep); + if (isInvalid) + break; + // FIXME: restrict this to "id" and ObjC classnames. + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); // The identifier + if (Tok.is(tok::less)) { + SourceLocation endProtoLoc; + llvm::SmallVector ProtocolRefs; + ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc); + llvm::SmallVector *ProtocolDecl = + new llvm::SmallVector; + DS.setProtocolQualifiers(ProtocolDecl); + Actions.FindProtocolDeclaration(Loc, + &ProtocolRefs[0], ProtocolRefs.size(), + *ProtocolDecl); + } + continue; + } + } + // FALL THROUGH. + default: + // If this is not a declaration specifier token, we're done reading decl + // specifiers. First verify that DeclSpec's are consistent. + DS.Finish(Diags, PP.getSourceManager(), getLang()); + return; + + // GNU attributes support. + case tok::kw___attribute: + DS.AddAttributes(ParseAttributes()); + continue; + + // storage-class-specifier + case tok::kw_typedef: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec); + break; + case tok::kw_extern: + if (DS.isThreadSpecified()) + Diag(Tok, diag::ext_thread_before, "extern"); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_extern, Loc, PrevSpec); + break; + case tok::kw___private_extern__: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_private_extern, Loc, PrevSpec); + break; + case tok::kw_static: + if (DS.isThreadSpecified()) + Diag(Tok, diag::ext_thread_before, "static"); + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_static, Loc, PrevSpec); + break; + case tok::kw_auto: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec); + break; + case tok::kw_register: + isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec); + break; + case tok::kw___thread: + isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2; + break; + + // type-specifiers + case tok::kw_short: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); + break; + case tok::kw_long: + if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); + else + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec); + break; + case tok::kw_signed: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); + break; + case tok::kw_unsigned: + isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); + break; + case tok::kw__Complex: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec); + break; + case tok::kw__Imaginary: + isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec); + break; + case tok::kw_void: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); + break; + case tok::kw_char: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); + break; + case tok::kw_int: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); + break; + case tok::kw_float: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); + break; + case tok::kw_double: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); + break; + case tok::kw_bool: // [C++ 2.11p1] + case tok::kw__Bool: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec); + break; + case tok::kw__Decimal32: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec); + break; + case tok::kw__Decimal64: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec); + break; + case tok::kw__Decimal128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec); + break; + + case tok::kw_struct: + case tok::kw_union: + ParseStructUnionSpecifier(DS); + continue; + case tok::kw_enum: + ParseEnumSpecifier(DS); + continue; + + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + continue; + + // type-qualifier + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, + getLang())*2; + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, + getLang())*2; + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, + getLang())*2; + break; + + // function-specifier + case tok::kw_inline: + isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec); + break; + } + // If the specifier combination wasn't legal, issue a diagnostic. + if (isInvalid) { + assert(PrevSpec && "Method did not return previous specifier!"); + if (isInvalid == 1) // Error. + Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec); + else // extwarn. + Diag(Tok, diag::ext_duplicate_declspec, PrevSpec); + } + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + } +} + +/// ParseTag - Parse "struct-or-union-or-class-or-enum identifier[opt]", where +/// the first token has already been read and has been turned into an instance +/// of DeclSpec::TST (TagType). This returns true if there is an error parsing, +/// otherwise it returns false and fills in Decl. +bool Parser::ParseTag(DeclTy *&Decl, unsigned TagType, SourceLocation StartLoc){ + AttributeList *Attr = 0; + // If attributes exist after tag, parse them. + if (Tok.is(tok::kw___attribute)) + Attr = ParseAttributes(); + + // Must have either 'struct name' or 'struct {...}'. + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_ident_lbrace); + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return true; + } + + // If an identifier is present, consume and remember it. + IdentifierInfo *Name = 0; + SourceLocation NameLoc; + if (Tok.is(tok::identifier)) { + Name = Tok.getIdentifierInfo(); + NameLoc = ConsumeToken(); + } + + // There are three options here. If we have 'struct foo;', then this is a + // forward declaration. If we have 'struct foo {...' then this is a + // definition. Otherwise we have something like 'struct foo xyz', a reference. + // + // This is needed to handle stuff like this right (C99 6.7.2.3p11): + // struct foo {..}; void bar() { struct foo; } <- new foo in bar. + // struct foo {..}; void bar() { struct foo x; } <- use of old foo. + // + Action::TagKind TK; + if (Tok.is(tok::l_brace)) + TK = Action::TK_Definition; + else if (Tok.is(tok::semi)) + TK = Action::TK_Declaration; + else + TK = Action::TK_Reference; + Decl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, Name, NameLoc, Attr); + return false; +} + + +/// ParseStructUnionSpecifier +/// struct-or-union-specifier: [C99 6.7.2.1] +/// struct-or-union identifier[opt] '{' struct-contents '}' +/// struct-or-union identifier +/// [GNU] struct-or-union attributes[opt] identifier[opt] '{' struct-contents +/// '}' attributes[opt] +/// [GNU] struct-or-union attributes[opt] identifier +/// struct-or-union: +/// 'struct' +/// 'union' +/// +void Parser::ParseStructUnionSpecifier(DeclSpec &DS) { + assert((Tok.is(tok::kw_struct) || Tok.is(tok::kw_union)) && + "Not a struct/union specifier"); + DeclSpec::TST TagType = + Tok.is(tok::kw_union) ? DeclSpec::TST_union : DeclSpec::TST_struct; + SourceLocation StartLoc = ConsumeToken(); + + // Parse the tag portion of this. + DeclTy *TagDecl; + if (ParseTag(TagDecl, TagType, StartLoc)) + return; + + // If there is a body, parse it and inform the actions module. + if (Tok.is(tok::l_brace)) + ParseStructUnionBody(StartLoc, TagType, TagDecl); + + const char *PrevSpec = 0; + if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, TagDecl)) + Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); +} + +/// ParseStructDeclaration - Parse a struct declaration without the terminating +/// semicolon. +/// +/// struct-declaration: +/// specifier-qualifier-list struct-declarator-list +/// [GNU] __extension__ struct-declaration +/// [GNU] specifier-qualifier-list +/// struct-declarator-list: +/// struct-declarator +/// struct-declarator-list ',' struct-declarator +/// [GNU] struct-declarator-list ',' attributes[opt] struct-declarator +/// struct-declarator: +/// declarator +/// [GNU] declarator attributes[opt] +/// declarator[opt] ':' constant-expression +/// [GNU] declarator[opt] ':' constant-expression attributes[opt] +/// +void Parser::ParseStructDeclaration(DeclTy *TagDecl, + llvm::SmallVectorImpl &FieldDecls) { + // FIXME: When __extension__ is specified, disable extension diagnostics. + if (Tok.is(tok::kw___extension__)) + ConsumeToken(); + + // Parse the common specifier-qualifiers-list piece. + DeclSpec DS; + SourceLocation SpecQualLoc = Tok.getLocation(); + ParseSpecifierQualifierList(DS); + // TODO: Does specifier-qualifier list correctly check that *something* is + // specified? + + // If there are no declarators, issue a warning. + if (Tok.is(tok::semi)) { + Diag(SpecQualLoc, diag::w_no_declarators); + return; + } + + // Read struct-declarators until we find the semicolon. + Declarator DeclaratorInfo(DS, Declarator::MemberContext); + + while (1) { + /// struct-declarator: declarator + /// struct-declarator: declarator[opt] ':' constant-expression + if (Tok.isNot(tok::colon)) + ParseDeclarator(DeclaratorInfo); + + ExprTy *BitfieldSize = 0; + if (Tok.is(tok::colon)) { + ConsumeToken(); + ExprResult Res = ParseConstantExpression(); + if (Res.isInvalid) { + SkipUntil(tok::semi, true, true); + } else { + BitfieldSize = Res.Val; + } + } + + // If attributes exist after the declarator, parse them. + if (Tok.is(tok::kw___attribute)) + DeclaratorInfo.AddAttributes(ParseAttributes()); + + // Install the declarator into the current TagDecl. + DeclTy *Field = Actions.ActOnField(CurScope, TagDecl, SpecQualLoc, + DeclaratorInfo, BitfieldSize); + FieldDecls.push_back(Field); + + // If we don't have a comma, it is either the end of the list (a ';') + // or an error, bail out. + if (Tok.isNot(tok::comma)) + return; + + // Consume the comma. + ConsumeToken(); + + // Parse the next declarator. + DeclaratorInfo.clear(); + + // Attributes are only allowed on the second declarator. + if (Tok.is(tok::kw___attribute)) + DeclaratorInfo.AddAttributes(ParseAttributes()); + } +} + +/// ParseStructUnionBody +/// struct-contents: +/// struct-declaration-list +/// [EXT] empty +/// [GNU] "struct-declaration-list" without terminatoring ';' +/// struct-declaration-list: +/// struct-declaration +/// struct-declaration-list struct-declaration +/// [OBC] '@' 'defs' '(' class-name ')' [TODO] +/// +void Parser::ParseStructUnionBody(SourceLocation RecordLoc, + unsigned TagType, DeclTy *TagDecl) { + SourceLocation LBraceLoc = ConsumeBrace(); + + // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in + // C++. + if (Tok.is(tok::r_brace)) + Diag(Tok, diag::ext_empty_struct_union_enum, + DeclSpec::getSpecifierName((DeclSpec::TST)TagType)); + + llvm::SmallVector FieldDecls; + + // While we still have something to read, read the declarations in the struct. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // Each iteration of this loop reads one struct-declaration. + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi); + ConsumeToken(); + continue; + } + ParseStructDeclaration(TagDecl, FieldDecls); + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if (Tok.is(tok::r_brace)) { + Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list); + break; + } else { + Diag(Tok, diag::err_expected_semi_decl_list); + // Skip to end of block or statement + SkipUntil(tok::r_brace, true, true); + } + } + + SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + + Actions.ActOnFields(CurScope, + RecordLoc,TagDecl,&FieldDecls[0],FieldDecls.size(), + LBraceLoc, RBraceLoc); + + AttributeList *AttrList = 0; + // If attributes exist after struct contents, parse them. + if (Tok.is(tok::kw___attribute)) + AttrList = ParseAttributes(); // FIXME: where should I put them? +} + + +/// ParseEnumSpecifier +/// enum-specifier: [C99 6.7.2.2] +/// 'enum' identifier[opt] '{' enumerator-list '}' +/// [C99] 'enum' identifier[opt] '{' enumerator-list ',' '}' +/// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] +/// '}' attributes[opt] +/// 'enum' identifier +/// [GNU] 'enum' attributes[opt] identifier +void Parser::ParseEnumSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw_enum) && "Not an enum specifier"); + SourceLocation StartLoc = ConsumeToken(); + + // Parse the tag portion of this. + DeclTy *TagDecl; + if (ParseTag(TagDecl, DeclSpec::TST_enum, StartLoc)) + return; + + if (Tok.is(tok::l_brace)) + ParseEnumBody(StartLoc, TagDecl); + + // TODO: semantic analysis on the declspec for enums. + const char *PrevSpec = 0; + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, PrevSpec, TagDecl)) + Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); +} + +/// ParseEnumBody - Parse a {} enclosed enumerator-list. +/// enumerator-list: +/// enumerator +/// enumerator-list ',' enumerator +/// enumerator: +/// enumeration-constant +/// enumeration-constant '=' constant-expression +/// enumeration-constant: +/// identifier +/// +void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { + SourceLocation LBraceLoc = ConsumeBrace(); + + // C does not allow an empty enumerator-list, C++ does [dcl.enum]. + if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) + Diag(Tok, diag::ext_empty_struct_union_enum, "enum"); + + llvm::SmallVector EnumConstantDecls; + + DeclTy *LastEnumConstDecl = 0; + + // Parse the enumerator-list. + while (Tok.is(tok::identifier)) { + IdentifierInfo *Ident = Tok.getIdentifierInfo(); + SourceLocation IdentLoc = ConsumeToken(); + + SourceLocation EqualLoc; + ExprTy *AssignedVal = 0; + if (Tok.is(tok::equal)) { + EqualLoc = ConsumeToken(); + ExprResult Res = ParseConstantExpression(); + if (Res.isInvalid) + SkipUntil(tok::comma, tok::r_brace, true, true); + else + AssignedVal = Res.Val; + } + + // Install the enumerator constant into EnumDecl. + DeclTy *EnumConstDecl = Actions.ActOnEnumConstant(CurScope, EnumDecl, + LastEnumConstDecl, + IdentLoc, Ident, + EqualLoc, AssignedVal); + EnumConstantDecls.push_back(EnumConstDecl); + LastEnumConstDecl = EnumConstDecl; + + if (Tok.isNot(tok::comma)) + break; + SourceLocation CommaLoc = ConsumeToken(); + + if (Tok.isNot(tok::identifier) && !getLang().C99) + Diag(CommaLoc, diag::ext_c99_enumerator_list_comma); + } + + // Eat the }. + MatchRHSPunctuation(tok::r_brace, LBraceLoc); + + Actions.ActOnEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0], + EnumConstantDecls.size()); + + DeclTy *AttrList = 0; + // If attributes exist after the identifier list, parse them. + if (Tok.is(tok::kw___attribute)) + AttrList = ParseAttributes(); // FIXME: where do they do? +} + +/// isTypeSpecifierQualifier - Return true if the current token could be the +/// start of a type-qualifier-list. +bool Parser::isTypeQualifier() const { + switch (Tok.getKind()) { + default: return false; + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + return true; + } +} + +/// isTypeSpecifierQualifier - Return true if the current token could be the +/// start of a specifier-qualifier-list. +bool Parser::isTypeSpecifierQualifier() const { + switch (Tok.getKind()) { + default: return false; + // GNU attributes support. + case tok::kw___attribute: + // GNU typeof support. + case tok::kw_typeof: + + // type-specifiers + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw__Complex: + case tok::kw__Imaginary: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw__Bool: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + + // struct-or-union-specifier + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + return true; + + // typedef-name + case tok::identifier: + return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0; + } +} + +/// isDeclarationSpecifier() - Return true if the current token is part of a +/// declaration specifier. +bool Parser::isDeclarationSpecifier() const { + switch (Tok.getKind()) { + default: return false; + // storage-class-specifier + case tok::kw_typedef: + case tok::kw_extern: + case tok::kw___private_extern__: + case tok::kw_static: + case tok::kw_auto: + case tok::kw_register: + case tok::kw___thread: + + // type-specifiers + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw__Complex: + case tok::kw__Imaginary: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_bool: + case tok::kw__Bool: + case tok::kw__Decimal32: + case tok::kw__Decimal64: + case tok::kw__Decimal128: + + // struct-or-union-specifier + case tok::kw_struct: + case tok::kw_union: + // enum-specifier + case tok::kw_enum: + + // type-qualifier + case tok::kw_const: + case tok::kw_volatile: + case tok::kw_restrict: + + // function-specifier + case tok::kw_inline: + + // GNU typeof support. + case tok::kw_typeof: + + // GNU attributes. + case tok::kw___attribute: + return true; + + // typedef-name + case tok::identifier: + return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0; + } +} + + +/// ParseTypeQualifierListOpt +/// type-qualifier-list: [C99 6.7.5] +/// type-qualifier +/// [GNU] attributes +/// type-qualifier-list type-qualifier +/// [GNU] type-qualifier-list attributes +/// +void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) { + while (1) { + int isInvalid = false; + const char *PrevSpec = 0; + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + default: + // If this is not a type-qualifier token, we're done reading type + // qualifiers. First verify that DeclSpec's are consistent. + DS.Finish(Diags, PP.getSourceManager(), getLang()); + return; + case tok::kw_const: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, + getLang())*2; + break; + case tok::kw_volatile: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, + getLang())*2; + break; + case tok::kw_restrict: + isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, + getLang())*2; + break; + case tok::kw___attribute: + DS.AddAttributes(ParseAttributes()); + continue; // do *not* consume the next token! + } + + // If the specifier combination wasn't legal, issue a diagnostic. + if (isInvalid) { + assert(PrevSpec && "Method did not return previous specifier!"); + if (isInvalid == 1) // Error. + Diag(Tok, diag::err_invalid_decl_spec_combination, PrevSpec); + else // extwarn. + Diag(Tok, diag::ext_duplicate_declspec, PrevSpec); + } + ConsumeToken(); + } +} + + +/// ParseDeclarator - Parse and verify a newly-initialized declarator. +/// +void Parser::ParseDeclarator(Declarator &D) { + /// This implements the 'declarator' production in the C grammar, then checks + /// for well-formedness and issues diagnostics. + ParseDeclaratorInternal(D); + + // TODO: validate D. + +} + +/// ParseDeclaratorInternal +/// declarator: [C99 6.7.5] +/// pointer[opt] direct-declarator +/// [C++] '&' declarator [C++ 8p4, dcl.decl] +/// [GNU] '&' restrict[opt] attributes[opt] declarator +/// +/// pointer: [C99 6.7.5] +/// '*' type-qualifier-list[opt] +/// '*' type-qualifier-list[opt] pointer +/// +void Parser::ParseDeclaratorInternal(Declarator &D) { + tok::TokenKind Kind = Tok.getKind(); + + // Not a pointer or C++ reference. + if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus)) + return ParseDirectDeclarator(D); + + // Otherwise, '*' -> pointer or '&' -> reference. + SourceLocation Loc = ConsumeToken(); // Eat the * or &. + + if (Kind == tok::star) { + // Is a pointer. + DeclSpec DS; + + ParseTypeQualifierListOpt(DS); + + // Recursively parse the declarator. + ParseDeclaratorInternal(D); + + // Remember that we parsed a pointer type, and remember the type-quals. + D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, + DS.TakeAttributes())); + } else { + // Is a reference + DeclSpec DS; + + // C++ 8.3.2p1: cv-qualified references are ill-formed except when the + // cv-qualifiers are introduced through the use of a typedef or of a + // template type argument, in which case the cv-qualifiers are ignored. + // + // [GNU] Retricted references are allowed. + // [GNU] Attributes on references are allowed. + ParseTypeQualifierListOpt(DS); + + if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(DS.getConstSpecLoc(), + diag::err_invalid_reference_qualifier_application, + "const"); + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + Diag(DS.getVolatileSpecLoc(), + diag::err_invalid_reference_qualifier_application, + "volatile"); + } + + // Recursively parse the declarator. + ParseDeclaratorInternal(D); + + // Remember that we parsed a reference type. It doesn't have type-quals. + D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, + DS.TakeAttributes())); + } +} + +/// ParseDirectDeclarator +/// direct-declarator: [C99 6.7.5] +/// identifier +/// '(' declarator ')' +/// [GNU] '(' attributes declarator ')' +/// [C90] direct-declarator '[' constant-expression[opt] ']' +/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' +/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' +/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' +/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' +/// direct-declarator '(' parameter-type-list ')' +/// direct-declarator '(' identifier-list[opt] ')' +/// [GNU] direct-declarator '(' parameter-forward-declarations +/// parameter-type-list[opt] ')' +/// +void Parser::ParseDirectDeclarator(Declarator &D) { + // Parse the first direct-declarator seen. + if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { + assert(Tok.getIdentifierInfo() && "Not an identifier?"); + D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + } else if (Tok.is(tok::l_paren)) { + // direct-declarator: '(' declarator ')' + // direct-declarator: '(' attributes declarator ')' + // Example: 'char (*X)' or 'int (*XX)(void)' + ParseParenDeclarator(D); + } else if (D.mayOmitIdentifier()) { + // This could be something simple like "int" (in which case the declarator + // portion is empty), if an abstract-declarator is allowed. + D.SetIdentifier(0, Tok.getLocation()); + } else { + // Expected identifier or '('. + Diag(Tok, diag::err_expected_ident_lparen); + D.SetIdentifier(0, Tok.getLocation()); + } + + assert(D.isPastIdentifier() && + "Haven't past the location of the identifier yet?"); + + while (1) { + if (Tok.is(tok::l_paren)) { + ParseParenDeclarator(D); + } else if (Tok.is(tok::l_square)) { + ParseBracketDeclarator(D); + } else { + break; + } + } +} + +/// ParseParenDeclarator - We parsed the declarator D up to a paren. This may +/// either be before the identifier (in which case these are just grouping +/// parens for precedence) or it may be after the identifier, in which case +/// these are function arguments. +/// +/// This method also handles this portion of the grammar: +/// parameter-type-list: [C99 6.7.5] +/// parameter-list +/// parameter-list ',' '...' +/// +/// parameter-list: [C99 6.7.5] +/// parameter-declaration +/// parameter-list ',' parameter-declaration +/// +/// parameter-declaration: [C99 6.7.5] +/// declaration-specifiers declarator +/// [GNU] declaration-specifiers declarator attributes +/// declaration-specifiers abstract-declarator[opt] +/// [GNU] declaration-specifiers abstract-declarator[opt] attributes +/// +/// identifier-list: [C99 6.7.5] +/// identifier +/// identifier-list ',' identifier +/// +void Parser::ParseParenDeclarator(Declarator &D) { + SourceLocation StartLoc = ConsumeParen(); + + // If we haven't past the identifier yet (or where the identifier would be + // stored, if this is an abstract declarator), then this is probably just + // grouping parens. + if (!D.isPastIdentifier()) { + // Okay, this is probably a grouping paren. However, if this could be an + // abstract-declarator, then this could also be the start of function + // arguments (consider 'void()'). + bool isGrouping; + + if (!D.mayOmitIdentifier()) { + // If this can't be an abstract-declarator, this *must* be a grouping + // paren, because we haven't seen the identifier yet. + isGrouping = true; + } else if (Tok.is(tok::r_paren) || // 'int()' is a function. + isDeclarationSpecifier()) { // 'int(int)' is a function. + // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is + // considered to be a type, not a K&R identifier-list. + isGrouping = false; + } else { + // Otherwise, this is a grouping paren, e.g. 'int (*X)' or 'int(X)'. + isGrouping = true; + } + + // If this is a grouping paren, handle: + // direct-declarator: '(' declarator ')' + // direct-declarator: '(' attributes declarator ')' + if (isGrouping) { + if (Tok.is(tok::kw___attribute)) + D.AddAttributes(ParseAttributes()); + + ParseDeclaratorInternal(D); + // Match the ')'. + MatchRHSPunctuation(tok::r_paren, StartLoc); + return; + } + + // Okay, if this wasn't a grouping paren, it must be the start of a function + // argument list. Recognize that this declarator will never have an + // identifier (and remember where it would have been), then fall through to + // the handling of argument lists. + D.SetIdentifier(0, Tok.getLocation()); + } + + // Okay, this is the parameter list of a function definition, or it is an + // identifier list of a K&R-style function. + bool IsVariadic; + bool HasPrototype; + bool ErrorEmitted = false; + + // Build up an array of information about the parsed arguments. + llvm::SmallVector ParamInfo; + llvm::SmallSet ParamsSoFar; + + if (Tok.is(tok::r_paren)) { + // int() -> no prototype, no '...'. + IsVariadic = false; + HasPrototype = false; + } else if (Tok.is(tok::identifier) && + // K&R identifier lists can't have typedefs as identifiers, per + // C99 6.7.5.3p11. + !Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { + // Identifier list. Note that '(' identifier-list ')' is only allowed for + // normal declarators, not for abstract-declarators. + assert(D.isPastIdentifier() && "Identifier (if present) must be passed!"); + + // If there was no identifier specified, either we are in an + // abstract-declarator, or we are in a parameter declarator which was found + // to be abstract. In abstract-declarators, identifier lists are not valid, + // diagnose this. + if (!D.getIdentifier()) + Diag(Tok, diag::ext_ident_list_in_param); + + // Remember this identifier in ParamInfo. + ParamInfo.push_back(DeclaratorChunk::ParamInfo(Tok.getIdentifierInfo(), + Tok.getLocation(), 0)); + + ConsumeToken(); + while (Tok.is(tok::comma)) { + // Eat the comma. + ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + ErrorEmitted = true; + break; + } + + IdentifierInfo *ParmII = Tok.getIdentifierInfo(); + + // Verify that the argument identifier has not already been mentioned. + if (!ParamsSoFar.insert(ParmII)) { + Diag(Tok.getLocation(), diag::err_param_redefinition,ParmII->getName()); + ParmII = 0; + } + + // Remember this identifier in ParamInfo. + if (ParmII) + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + Tok.getLocation(), 0)); + + // Eat the identifier. + ConsumeToken(); + } + + // K&R 'prototype'. + IsVariadic = false; + HasPrototype = false; + } else { + // Finally, a normal, non-empty parameter type list. + + // Enter function-declaration scope, limiting any declarators for struct + // tags to the function prototype scope. + // FIXME: is this needed? + EnterScope(Scope::DeclScope); + + IsVariadic = false; + while (1) { + if (Tok.is(tok::ellipsis)) { + IsVariadic = true; + + // Check to see if this is "void(...)" which is not allowed. + if (ParamInfo.empty()) { + // Otherwise, parse parameter type list. If it starts with an + // ellipsis, diagnose the malformed function. + Diag(Tok, diag::err_ellipsis_first_arg); + IsVariadic = false; // Treat this like 'void()'. + } + + // Consume the ellipsis. + ConsumeToken(); + break; + } + + SourceLocation DSStart = Tok.getLocation(); + + // Parse the declaration-specifiers. + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + + // Parse the declarator. This is "PrototypeContext", because we must + // accept either 'declarator' or 'abstract-declarator' here. + Declarator ParmDecl(DS, Declarator::PrototypeContext); + ParseDeclarator(ParmDecl); + + // Parse GNU attributes, if present. + if (Tok.is(tok::kw___attribute)) + ParmDecl.AddAttributes(ParseAttributes()); + + // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. + // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted. + if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && + DS.getStorageClassSpec() != DeclSpec::SCS_register) { + Diag(DS.getStorageClassSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + if (DS.isThreadSpecified()) { + Diag(DS.getThreadSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + + // Inform the actions module about the parameter declarator, so it gets + // added to the current scope. + Action::TypeResult ParamTy = + Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); + + // Remember this parsed parameter in ParamInfo. + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + + // Verify that the argument identifier has not already been mentioned. + if (ParmII && !ParamsSoFar.insert(ParmII)) { + Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition, + ParmII->getName()); + ParmII = 0; + } + + // If no parameter was specified, verify that *something* was specified, + // otherwise we have a missing type and identifier. + if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && + ParmDecl.getIdentifier() == 0 && ParmDecl.getNumTypeObjects() == 0) { + Diag(DSStart, diag::err_missing_param); + } else if (!DS.hasTypeSpecifier() && + (getLang().C99 || getLang().CPlusPlus)) { + // Otherwise, if something was specified but a type specifier wasn't, + // (e.g. "x" or "restrict x" or "restrict"), this is a use of implicit + // int. This is valid in C90, but not in C99 or C++. + if (ParmII) + Diag(ParmDecl.getIdentifierLoc(), + diag::ext_param_requires_type_specifier, ParmII->getName()); + else + Diag(DSStart, diag::ext_anon_param_requires_type_specifier); + } + + ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), + ParmDecl.getDeclSpec().TakeAttributes())); + + // If the next token is a comma, consume it and keep reading arguments. + if (Tok.isNot(tok::comma)) break; + + // Consume the comma. + ConsumeToken(); + } + + HasPrototype = true; + + // Leave prototype scope. + ExitScope(); + } + + // Remember that we parsed a function type, and remember the attributes. + if (!ErrorEmitted) + D.AddTypeInfo(DeclaratorChunk::getFunction(HasPrototype, IsVariadic, + &ParamInfo[0], ParamInfo.size(), + StartLoc)); + + // If we have the closing ')', eat it and we're done. + if (Tok.is(tok::r_paren)) { + ConsumeParen(); + } else { + // If an error happened earlier parsing something else in the proto, don't + // issue another error. + if (!ErrorEmitted) + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren); + } +} + + +/// [C90] direct-declarator '[' constant-expression[opt] ']' +/// [C99] direct-declarator '[' type-qual-list[opt] assignment-expr[opt] ']' +/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']' +/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']' +/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']' +void Parser::ParseBracketDeclarator(Declarator &D) { + SourceLocation StartLoc = ConsumeBracket(); + + // If valid, this location is the position where we read the 'static' keyword. + SourceLocation StaticLoc; + if (Tok.is(tok::kw_static)) + StaticLoc = ConsumeToken(); + + // If there is a type-qualifier-list, read it now. + DeclSpec DS; + ParseTypeQualifierListOpt(DS); + + // If we haven't already read 'static', check to see if there is one after the + // type-qualifier-list. + if (!StaticLoc.isValid() && Tok.is(tok::kw_static)) + StaticLoc = ConsumeToken(); + + // Handle "direct-declarator [ type-qual-list[opt] * ]". + bool isStar = false; + ExprResult NumElements(false); + if (Tok.is(tok::star)) { + // Remember the '*' token, in case we have to un-get it. + Token StarTok = Tok; + ConsumeToken(); + + // Check that the ']' token is present to avoid incorrectly parsing + // expressions starting with '*' as [*]. + if (Tok.is(tok::r_square)) { + if (StaticLoc.isValid()) + Diag(StaticLoc, diag::err_unspecified_vla_size_with_static); + StaticLoc = SourceLocation(); // Drop the static. + isStar = true; + } else { + // Otherwise, the * must have been some expression (such as '*ptr') that + // started an assignment-expr. We already consumed the token, but now we + // need to reparse it. This handles cases like 'X[*p + 4]' + NumElements = ParseAssignmentExpressionWithLeadingStar(StarTok); + } + } else if (Tok.isNot(tok::r_square)) { + // Parse the assignment-expression now. + NumElements = ParseAssignmentExpression(); + } + + // If there was an error parsing the assignment-expression, recover. + if (NumElements.isInvalid) { + // If the expression was invalid, skip it. + SkipUntil(tok::r_square); + return; + } + + MatchRHSPunctuation(tok::r_square, StartLoc); + + // If C99 isn't enabled, emit an ext-warn if the arg list wasn't empty and if + // it was not a constant expression. + if (!getLang().C99) { + // TODO: check C90 array constant exprness. + if (isStar || StaticLoc.isValid() || + 0/*TODO: NumElts is not a C90 constantexpr */) + Diag(StartLoc, diag::ext_c99_array_usage); + } + + // Remember that we parsed a pointer type, and remember the type-quals. + D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), + StaticLoc.isValid(), isStar, + NumElements.Val, StartLoc)); +} + +/// [GNU] typeof-specifier: +/// typeof ( expressions ) +/// typeof ( type-name ) +/// +void Parser::ParseTypeofSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier"); + const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); + SourceLocation StartLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName()); + return; + } + SourceLocation LParenLoc = ConsumeParen(), RParenLoc; + + if (isTypeSpecifierQualifier()) { + TypeTy *Ty = ParseTypeName(); + + assert(Ty && "Parser::ParseTypeofSpecifier(): missing type"); + + if (Tok.isNot(tok::r_paren)) { + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return; + } + RParenLoc = ConsumeParen(); + const char *PrevSpec = 0; + // Check for duplicate type specifiers (e.g. "int typeof(int)"). + if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec, Ty)) + Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); + } else { // we have an expression. + ExprResult Result = ParseExpression(); + + if (Result.isInvalid || Tok.isNot(tok::r_paren)) { + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return; + } + RParenLoc = ConsumeParen(); + const char *PrevSpec = 0; + // Check for duplicate type specifiers (e.g. "int typeof(int)"). + if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, + Result.Val)) + Diag(StartLoc, diag::err_invalid_decl_spec_combination, PrevSpec); + } +} + diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp new file mode 100644 index 00000000000..46dcb574819 --- /dev/null +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -0,0 +1,119 @@ +//===--- ParseDeclCXX.cpp - C++ Declaration Parsing -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the C++ Declaration portions of the Parser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/Scope.h" +#include "clang/Basic/Diagnostic.h" +using namespace clang; + +/// ParseNamespace - We know that the current token is a namespace keyword. This +/// may either be a top level namespace or a block-level namespace alias. +/// +/// namespace-definition: [C++ 7.3: basic.namespace] +/// named-namespace-definition +/// unnamed-namespace-definition +/// +/// unnamed-namespace-definition: +/// 'namespace' attributes[opt] '{' namespace-body '}' +/// +/// named-namespace-definition: +/// original-namespace-definition +/// extension-namespace-definition +/// +/// original-namespace-definition: +/// 'namespace' identifier attributes[opt] '{' namespace-body '}' +/// +/// extension-namespace-definition: +/// 'namespace' original-namespace-name '{' namespace-body '}' +/// +/// namespace-alias-definition: [C++ 7.3.2: namespace.alias] +/// 'namespace' identifier '=' qualified-namespace-specifier ';' +/// +Parser::DeclTy *Parser::ParseNamespace(unsigned Context) { + assert(Tok.is(tok::kw_namespace) && "Not a namespace!"); + SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'. + + SourceLocation IdentLoc; + IdentifierInfo *Ident = 0; + + if (Tok.is(tok::identifier)) { + Ident = Tok.getIdentifierInfo(); + IdentLoc = ConsumeToken(); // eat the identifier. + } + + // Read label attributes, if present. + DeclTy *AttrList = 0; + if (Tok.is(tok::kw___attribute)) + // FIXME: save these somewhere. + AttrList = ParseAttributes(); + + if (Tok.is(tok::equal)) { + // FIXME: Verify no attributes were present. + // FIXME: parse this. + } else if (Tok.is(tok::l_brace)) { + SourceLocation LBrace = ConsumeBrace(); + // FIXME: push a scope, push a namespace decl. + + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // FIXME capture the decls. + ParseExternalDeclaration(); + } + + SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); + + // FIXME: act on this. + } else { + unsigned D = Ident ? diag::err_expected_lbrace : + diag::err_expected_ident_lbrace; + Diag(Tok.getLocation(), D); + } + + return 0; +} + +/// ParseLinkage - We know that the current token is a string_literal +/// and just before that, that extern was seen. +/// +/// linkage-specification: [C++ 7.5p2: dcl.link] +/// 'extern' string-literal '{' declaration-seq[opt] '}' +/// 'extern' string-literal declaration +/// +Parser::DeclTy *Parser::ParseLinkage(unsigned Context) { + assert(Tok.is(tok::string_literal) && "Not a stringliteral!"); + llvm::SmallVector LangBuffer; + // LangBuffer is guaranteed to be big enough. + LangBuffer.resize(Tok.getLength()); + const char *LangBufPtr = &LangBuffer[0]; + unsigned StrSize = PP.getSpelling(Tok, LangBufPtr); + + SourceLocation Loc = ConsumeStringToken(); + DeclTy *D = 0; + SourceLocation LBrace, RBrace; + + if (Tok.isNot(tok::l_brace)) { + D = ParseDeclaration(Context); + } else { + LBrace = ConsumeBrace(); + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // FIXME capture the decls. + D = ParseExternalDeclaration(); + } + + RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); + } + + if (!D) + return 0; + + return Actions.ActOnLinkageSpec(Loc, LBrace, RBrace, LangBufPtr, StrSize, D); +} diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp new file mode 100644 index 00000000000..46714b73ea7 --- /dev/null +++ b/clang/lib/Parse/ParseExpr.cpp @@ -0,0 +1,1081 @@ +//===--- ParseExpr.cpp - Expression Parsing -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expression parsing implementation. Expressions in +// C99 basically consist of a bunch of binary operators with unary operators and +// other random stuff at the leaves. +// +// In the C99 grammar, these unary operators bind tightest and are represented +// as the 'cast-expression' production. Everything else is either a binary +// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are +// handled by ParseCastExpression, the higher level pieces are handled by +// ParseBinaryExpression. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +/// PrecedenceLevels - These are precedences for the binary/ternary operators in +/// the C99 grammar. These have been named to relate with the C99 grammar +/// productions. Low precedences numbers bind more weakly than high numbers. +namespace prec { + enum Level { + Unknown = 0, // Not binary operator. + Comma = 1, // , + Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= + Conditional = 3, // ? + LogicalOr = 4, // || + LogicalAnd = 5, // && + InclusiveOr = 6, // | + ExclusiveOr = 7, // ^ + And = 8, // & + Equality = 9, // ==, != + Relational = 10, // >=, <=, >, < + Shift = 11, // <<, >> + Additive = 12, // -, + + Multiplicative = 13 // *, /, % + }; +} + + +/// getBinOpPrecedence - Return the precedence of the specified binary operator +/// token. This returns: +/// +static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { + switch (Kind) { + default: return prec::Unknown; + case tok::comma: return prec::Comma; + case tok::equal: + case tok::starequal: + case tok::slashequal: + case tok::percentequal: + case tok::plusequal: + case tok::minusequal: + case tok::lesslessequal: + case tok::greatergreaterequal: + case tok::ampequal: + case tok::caretequal: + case tok::pipeequal: return prec::Assignment; + case tok::question: return prec::Conditional; + case tok::pipepipe: return prec::LogicalOr; + case tok::ampamp: return prec::LogicalAnd; + case tok::pipe: return prec::InclusiveOr; + case tok::caret: return prec::ExclusiveOr; + case tok::amp: return prec::And; + case tok::exclaimequal: + case tok::equalequal: return prec::Equality; + case tok::lessequal: + case tok::less: + case tok::greaterequal: + case tok::greater: return prec::Relational; + case tok::lessless: + case tok::greatergreater: return prec::Shift; + case tok::plus: + case tok::minus: return prec::Additive; + case tok::percent: + case tok::slash: + case tok::star: return prec::Multiplicative; + } +} + + +/// ParseExpression - Simple precedence-based parser for binary/ternary +/// operators. +/// +/// Note: we diverge from the C99 grammar when parsing the assignment-expression +/// production. C99 specifies that the LHS of an assignment operator should be +/// parsed as a unary-expression, but consistency dictates that it be a +/// conditional-expession. In practice, the important thing here is that the +/// LHS of an assignment has to be an l-value, which productions between +/// unary-expression and conditional-expression don't produce. Because we want +/// consistency, we parse the LHS as a conditional-expression, then check for +/// l-value-ness in semantic analysis stages. +/// +/// multiplicative-expression: [C99 6.5.5] +/// cast-expression +/// multiplicative-expression '*' cast-expression +/// multiplicative-expression '/' cast-expression +/// multiplicative-expression '%' cast-expression +/// +/// additive-expression: [C99 6.5.6] +/// multiplicative-expression +/// additive-expression '+' multiplicative-expression +/// additive-expression '-' multiplicative-expression +/// +/// shift-expression: [C99 6.5.7] +/// additive-expression +/// shift-expression '<<' additive-expression +/// shift-expression '>>' additive-expression +/// +/// relational-expression: [C99 6.5.8] +/// shift-expression +/// relational-expression '<' shift-expression +/// relational-expression '>' shift-expression +/// relational-expression '<=' shift-expression +/// relational-expression '>=' shift-expression +/// +/// equality-expression: [C99 6.5.9] +/// relational-expression +/// equality-expression '==' relational-expression +/// equality-expression '!=' relational-expression +/// +/// AND-expression: [C99 6.5.10] +/// equality-expression +/// AND-expression '&' equality-expression +/// +/// exclusive-OR-expression: [C99 6.5.11] +/// AND-expression +/// exclusive-OR-expression '^' AND-expression +/// +/// inclusive-OR-expression: [C99 6.5.12] +/// exclusive-OR-expression +/// inclusive-OR-expression '|' exclusive-OR-expression +/// +/// logical-AND-expression: [C99 6.5.13] +/// inclusive-OR-expression +/// logical-AND-expression '&&' inclusive-OR-expression +/// +/// logical-OR-expression: [C99 6.5.14] +/// logical-AND-expression +/// logical-OR-expression '||' logical-AND-expression +/// +/// conditional-expression: [C99 6.5.15] +/// logical-OR-expression +/// logical-OR-expression '?' expression ':' conditional-expression +/// [GNU] logical-OR-expression '?' ':' conditional-expression +/// +/// assignment-expression: [C99 6.5.16] +/// conditional-expression +/// unary-expression assignment-operator assignment-expression +/// [C++] throw-expression [C++ 15] +/// +/// assignment-operator: one of +/// = *= /= %= += -= <<= >>= &= ^= |= +/// +/// expression: [C99 6.5.17] +/// assignment-expression +/// expression ',' assignment-expression +/// +Parser::ExprResult Parser::ParseExpression() { + if (Tok.is(tok::kw_throw)) + return ParseThrowExpression(); + + ExprResult LHS = ParseCastExpression(false); + if (LHS.isInvalid) return LHS; + + return ParseRHSOfBinaryExpression(LHS, prec::Comma); +} + +/// This routine is called when the '@' is seen and consumed. +/// Current token is an Identifier and is not a 'try'. This +/// routine is necessary to disambiguate @try-statement from, +/// for example, @encode-expression. +/// +Parser::ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { + ExprResult LHS = ParseObjCAtExpression(AtLoc); + if (LHS.isInvalid) return LHS; + + return ParseRHSOfBinaryExpression(LHS, prec::Comma); +} + +/// ParseAssignmentExpression - Parse an expr that doesn't include commas. +/// +Parser::ExprResult Parser::ParseAssignmentExpression() { + if (Tok.is(tok::kw_throw)) + return ParseThrowExpression(); + + ExprResult LHS = ParseCastExpression(false); + if (LHS.isInvalid) return LHS; + + return ParseRHSOfBinaryExpression(LHS, prec::Assignment); +} + +Parser::ExprResult Parser::ParseConstantExpression() { + ExprResult LHS = ParseCastExpression(false); + if (LHS.isInvalid) return LHS; + + return ParseRHSOfBinaryExpression(LHS, prec::Conditional); +} + +/// ParseExpressionWithLeadingIdentifier - This special purpose method is used +/// in contexts where we have already consumed an identifier (which we saved in +/// 'IdTok'), then discovered that the identifier was really the leading token +/// of part of an expression. For example, in "A[1]+B", we consumed "A" (which +/// is now in 'IdTok') and the current token is "[". +Parser::ExprResult Parser:: +ParseExpressionWithLeadingIdentifier(const Token &IdTok) { + // We know that 'IdTok' must correspond to this production: + // primary-expression: identifier + + // Let the actions module handle the identifier. + ExprResult Res = Actions.ActOnIdentifierExpr(CurScope, IdTok.getLocation(), + *IdTok.getIdentifierInfo(), + Tok.is(tok::l_paren)); + + // Because we have to parse an entire cast-expression before starting the + // ParseRHSOfBinaryExpression method (which parses any trailing binops), we + // need to handle the 'postfix-expression' rules. We do this by invoking + // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes: + Res = ParsePostfixExpressionSuffix(Res); + if (Res.isInvalid) return Res; + + // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is + // done, we know we don't have to do anything for cast-expression, because the + // only non-postfix-expression production starts with a '(' token, and we know + // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression + // to consume any trailing operators (e.g. "+" in this example) and connected + // chunks of the expression. + return ParseRHSOfBinaryExpression(Res, prec::Comma); +} + +/// ParseExpressionWithLeadingIdentifier - This special purpose method is used +/// in contexts where we have already consumed an identifier (which we saved in +/// 'IdTok'), then discovered that the identifier was really the leading token +/// of part of an assignment-expression. For example, in "A[1]+B", we consumed +/// "A" (which is now in 'IdTok') and the current token is "[". +Parser::ExprResult Parser:: +ParseAssignmentExprWithLeadingIdentifier(const Token &IdTok) { + // We know that 'IdTok' must correspond to this production: + // primary-expression: identifier + + // Let the actions module handle the identifier. + ExprResult Res = Actions.ActOnIdentifierExpr(CurScope, IdTok.getLocation(), + *IdTok.getIdentifierInfo(), + Tok.is(tok::l_paren)); + + // Because we have to parse an entire cast-expression before starting the + // ParseRHSOfBinaryExpression method (which parses any trailing binops), we + // need to handle the 'postfix-expression' rules. We do this by invoking + // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes: + Res = ParsePostfixExpressionSuffix(Res); + if (Res.isInvalid) return Res; + + // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is + // done, we know we don't have to do anything for cast-expression, because the + // only non-postfix-expression production starts with a '(' token, and we know + // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression + // to consume any trailing operators (e.g. "+" in this example) and connected + // chunks of the expression. + return ParseRHSOfBinaryExpression(Res, prec::Assignment); +} + + +/// ParseAssignmentExpressionWithLeadingStar - This special purpose method is +/// used in contexts where we have already consumed a '*' (which we saved in +/// 'StarTok'), then discovered that the '*' was really the leading token of an +/// expression. For example, in "*(int*)P+B", we consumed "*" (which is +/// now in 'StarTok') and the current token is "(". +Parser::ExprResult Parser:: +ParseAssignmentExpressionWithLeadingStar(const Token &StarTok) { + // We know that 'StarTok' must correspond to this production: + // unary-expression: unary-operator cast-expression + // where 'unary-operator' is '*'. + + // Parse the cast-expression that follows the '*'. This will parse the + // "*(int*)P" part of "*(int*)P+B". + ExprResult Res = ParseCastExpression(false); + if (Res.isInvalid) return Res; + + // Combine StarTok + Res to get the new AST for the combined expression.. + Res = Actions.ActOnUnaryOp(StarTok.getLocation(), tok::star, Res.Val); + if (Res.isInvalid) return Res; + + + // We have to parse an entire cast-expression before starting the + // ParseRHSOfBinaryExpression method (which parses any trailing binops). Since + // we know that the only production above us is the cast-expression + // production, and because the only alternative productions start with a '(' + // token (we know we had a '*'), there is no work to do to get a whole + // cast-expression. + + // At this point, the "*(int*)P" part of "*(int*)P+B" has been consumed. Once + // this is done, we can invoke ParseRHSOfBinaryExpression to consume any + // trailing operators (e.g. "+" in this example) and connected chunks of the + // assignment-expression. + return ParseRHSOfBinaryExpression(Res, prec::Assignment); +} + + +/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with +/// LHS and has a precedence of at least MinPrec. +Parser::ExprResult +Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { + unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind()); + SourceLocation ColonLoc; + + while (1) { + // If this token has a lower precedence than we are allowed to parse (e.g. + // because we are called recursively, or because the token is not a binop), + // then we are done! + if (NextTokPrec < MinPrec) + return LHS; + + // Consume the operator, saving the operator token for error reporting. + Token OpToken = Tok; + ConsumeToken(); + + // Special case handling for the ternary operator. + ExprResult TernaryMiddle(true); + if (NextTokPrec == prec::Conditional) { + if (Tok.isNot(tok::colon)) { + // Handle this production specially: + // logical-OR-expression '?' expression ':' conditional-expression + // In particular, the RHS of the '?' is 'expression', not + // 'logical-OR-expression' as we might expect. + TernaryMiddle = ParseExpression(); + if (TernaryMiddle.isInvalid) { + Actions.DeleteExpr(LHS.Val); + return TernaryMiddle; + } + } else { + // Special case handling of "X ? Y : Z" where Y is empty: + // logical-OR-expression '?' ':' conditional-expression [GNU] + TernaryMiddle = ExprResult(false); + Diag(Tok, diag::ext_gnu_conditional_expr); + } + + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon); + Diag(OpToken, diag::err_matching, "?"); + Actions.DeleteExpr(LHS.Val); + Actions.DeleteExpr(TernaryMiddle.Val); + return ExprResult(true); + } + + // Eat the colon. + ColonLoc = ConsumeToken(); + } + + // Parse another leaf here for the RHS of the operator. + ExprResult RHS = ParseCastExpression(false); + if (RHS.isInvalid) { + Actions.DeleteExpr(LHS.Val); + Actions.DeleteExpr(TernaryMiddle.Val); + return RHS; + } + + // Remember the precedence of this operator and get the precedence of the + // operator immediately to the right of the RHS. + unsigned ThisPrec = NextTokPrec; + NextTokPrec = getBinOpPrecedence(Tok.getKind()); + + // Assignment and conditional expressions are right-associative. + bool isRightAssoc = ThisPrec == prec::Conditional || + ThisPrec == prec::Assignment; + + // Get the precedence of the operator to the right of the RHS. If it binds + // more tightly with RHS than we do, evaluate it completely first. + if (ThisPrec < NextTokPrec || + (ThisPrec == NextTokPrec && isRightAssoc)) { + // If this is left-associative, only parse things on the RHS that bind + // more tightly than the current operator. If it is left-associative, it + // is okay, to bind exactly as tightly. For example, compile A=B=C=D as + // A=(B=(C=D)), where each paren is a level of recursion here. + RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec + !isRightAssoc); + if (RHS.isInvalid) { + Actions.DeleteExpr(LHS.Val); + Actions.DeleteExpr(TernaryMiddle.Val); + return RHS; + } + + NextTokPrec = getBinOpPrecedence(Tok.getKind()); + } + assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); + + if (!LHS.isInvalid) { + // Combine the LHS and RHS into the LHS (e.g. build AST). + if (TernaryMiddle.isInvalid) + LHS = Actions.ActOnBinOp(OpToken.getLocation(), OpToken.getKind(), + LHS.Val, RHS.Val); + else + LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, + LHS.Val, TernaryMiddle.Val, RHS.Val); + } else { + // We had a semantic error on the LHS. Just free the RHS and continue. + Actions.DeleteExpr(TernaryMiddle.Val); + Actions.DeleteExpr(RHS.Val); + } + } +} + +/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is +/// true, parse a unary-expression. +/// +/// cast-expression: [C99 6.5.4] +/// unary-expression +/// '(' type-name ')' cast-expression +/// +/// unary-expression: [C99 6.5.3] +/// postfix-expression +/// '++' unary-expression +/// '--' unary-expression +/// unary-operator cast-expression +/// 'sizeof' unary-expression +/// 'sizeof' '(' type-name ')' +/// [GNU] '__alignof' unary-expression +/// [GNU] '__alignof' '(' type-name ')' +/// [GNU] '&&' identifier +/// +/// unary-operator: one of +/// '&' '*' '+' '-' '~' '!' +/// [GNU] '__extension__' '__real' '__imag' +/// +/// primary-expression: [C99 6.5.1] +/// identifier +/// constant +/// string-literal +/// [C++] boolean-literal [C++ 2.13.5] +/// '(' expression ')' +/// '__func__' [C99 6.4.2.2] +/// [GNU] '__FUNCTION__' +/// [GNU] '__PRETTY_FUNCTION__' +/// [GNU] '(' compound-statement ')' +/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' +/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' +/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' +/// assign-expr ')' +/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [OBJC] '[' objc-message-expr ']' +/// [OBJC] '@selector' '(' objc-selector-arg ')' +/// [OBJC] '@protocol' '(' identifier ')' +/// [OBJC] '@encode' '(' type-name ')' +/// [OBJC] objc-string-literal +/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] +/// +/// constant: [C99 6.4.4] +/// integer-constant +/// floating-constant +/// enumeration-constant -> identifier +/// character-constant +/// +Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { + ExprResult Res; + tok::TokenKind SavedKind = Tok.getKind(); + + // This handles all of cast-expression, unary-expression, postfix-expression, + // and primary-expression. We handle them together like this for efficiency + // and to simplify handling of an expression starting with a '(' token: which + // may be one of a parenthesized expression, cast-expression, compound literal + // expression, or statement expression. + // + // If the parsed tokens consist of a primary-expression, the cases below + // call ParsePostfixExpressionSuffix to handle the postfix expression + // suffixes. Cases that cannot be followed by postfix exprs should + // return without invoking ParsePostfixExpressionSuffix. + switch (SavedKind) { + case tok::l_paren: { + // If this expression is limited to being a unary-expression, the parent can + // not start a cast expression. + ParenParseOption ParenExprType = + isUnaryExpression ? CompoundLiteral : CastExpr; + TypeTy *CastTy; + SourceLocation LParenLoc = Tok.getLocation(); + SourceLocation RParenLoc; + Res = ParseParenExpression(ParenExprType, CastTy, RParenLoc); + if (Res.isInvalid) return Res; + + switch (ParenExprType) { + case SimpleExpr: break; // Nothing else to do. + case CompoundStmt: break; // Nothing else to do. + case CompoundLiteral: + // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of + // postfix-expression exist, parse them now. + break; + case CastExpr: + // We parsed '(' type-name ')' and the thing after it wasn't a '{'. Parse + // the cast-expression that follows it next. + // TODO: For cast expression with CastTy. + Res = ParseCastExpression(false); + if (!Res.isInvalid) + Res = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc, Res.Val); + return Res; + } + + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); + } + + // primary-expression + case tok::numeric_constant: + // constant: integer-constant + // constant: floating-constant + + Res = Actions.ActOnNumericConstant(Tok); + ConsumeToken(); + + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); + + case tok::kw_true: + case tok::kw_false: + return ParseCXXBoolLiteral(); + + case tok::identifier: { // primary-expression: identifier + // constant: enumeration-constant + // Consume the identifier so that we can see if it is followed by a '('. + // Function designators are allowed to be undeclared (C99 6.5.1p2), so we + // need to know whether or not this identifier is a function designator or + // not. + IdentifierInfo &II = *Tok.getIdentifierInfo(); + SourceLocation L = ConsumeToken(); + Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren)); + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); + } + case tok::char_constant: // constant: character-constant + Res = Actions.ActOnCharacterConstant(Tok); + ConsumeToken(); + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); + case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] + case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] + case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] + Res = Actions.ActOnPreDefinedExpr(Tok.getLocation(), SavedKind); + ConsumeToken(); + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); + case tok::string_literal: // primary-expression: string-literal + case tok::wide_string_literal: + Res = ParseStringLiteralExpression(); + if (Res.isInvalid) return Res; + // This can be followed by postfix-expr pieces (e.g. "foo"[1]). + return ParsePostfixExpressionSuffix(Res); + case tok::kw___builtin_va_arg: + case tok::kw___builtin_offsetof: + case tok::kw___builtin_choose_expr: + case tok::kw___builtin_overload: + case tok::kw___builtin_types_compatible_p: + return ParseBuiltinPrimaryExpression(); + case tok::plusplus: // unary-expression: '++' unary-expression + case tok::minusminus: { // unary-expression: '--' unary-expression + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(true); + if (!Res.isInvalid) + Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); + return Res; + } + case tok::amp: // unary-expression: '&' cast-expression + case tok::star: // unary-expression: '*' cast-expression + case tok::plus: // unary-expression: '+' cast-expression + case tok::minus: // unary-expression: '-' cast-expression + case tok::tilde: // unary-expression: '~' cast-expression + case tok::exclaim: // unary-expression: '!' cast-expression + case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] + case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(false); + if (!Res.isInvalid) + Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); + return Res; + } + + case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] + // __extension__ silences extension warnings in the subexpression. + bool SavedExtWarn = Diags.getWarnOnExtensions(); + Diags.setWarnOnExtensions(false); + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(false); + if (!Res.isInvalid) + Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); + Diags.setWarnOnExtensions(SavedExtWarn); + return Res; + } + case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression + // unary-expression: 'sizeof' '(' type-name ')' + case tok::kw___alignof: // unary-expression: '__alignof' unary-expression + // unary-expression: '__alignof' '(' type-name ')' + return ParseSizeofAlignofExpression(); + case tok::ampamp: { // unary-expression: '&&' identifier + SourceLocation AmpAmpLoc = ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return ExprResult(true); + } + + Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); + Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), + Tok.getIdentifierInfo()); + ConsumeToken(); + return Res; + } + case tok::kw_const_cast: + case tok::kw_dynamic_cast: + case tok::kw_reinterpret_cast: + case tok::kw_static_cast: + return ParseCXXCasts(); + case tok::at: { + SourceLocation AtLoc = ConsumeToken(); + return ParseObjCAtExpression(AtLoc); + } + case tok::l_square: + // These can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); + default: + Diag(Tok, diag::err_expected_expression); + return ExprResult(true); + } + + // unreachable. + abort(); +} + +/// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression +/// is parsed, this method parses any suffixes that apply. +/// +/// postfix-expression: [C99 6.5.2] +/// primary-expression +/// postfix-expression '[' expression ']' +/// postfix-expression '(' argument-expression-list[opt] ')' +/// postfix-expression '.' identifier +/// postfix-expression '->' identifier +/// postfix-expression '++' +/// postfix-expression '--' +/// '(' type-name ')' '{' initializer-list '}' +/// '(' type-name ')' '{' initializer-list ',' '}' +/// +/// argument-expression-list: [C99 6.5.2] +/// argument-expression +/// argument-expression-list ',' assignment-expression +/// +Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { + + // Now that the primary-expression piece of the postfix-expression has been + // parsed, see if there are any postfix-expression pieces here. + SourceLocation Loc; + while (1) { + switch (Tok.getKind()) { + default: // Not a postfix-expression suffix. + return LHS; + case tok::l_square: { // postfix-expression: p-e '[' expression ']' + Loc = ConsumeBracket(); + ExprResult Idx = ParseExpression(); + + SourceLocation RLoc = Tok.getLocation(); + + if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square)) + LHS = Actions.ActOnArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc); + else + LHS = ExprResult(true); + + // Match the ']'. + MatchRHSPunctuation(tok::r_square, Loc); + break; + } + + case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')' + llvm::SmallVector ArgExprs; + llvm::SmallVector CommaLocs; + + Loc = ConsumeParen(); + + if (Tok.isNot(tok::r_paren)) { + while (1) { + ExprResult ArgExpr = ParseAssignmentExpression(); + if (ArgExpr.isInvalid) { + SkipUntil(tok::r_paren); + return ExprResult(true); + } else + ArgExprs.push_back(ArgExpr.Val); + + if (Tok.isNot(tok::comma)) + break; + // Move to the next argument, remember where the comma was. + CommaLocs.push_back(ConsumeToken()); + } + } + + // Match the ')'. + if (!LHS.isInvalid && Tok.is(tok::r_paren)) { + assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& + "Unexpected number of commas!"); + LHS = Actions.ActOnCallExpr(LHS.Val, Loc, &ArgExprs[0], ArgExprs.size(), + &CommaLocs[0], Tok.getLocation()); + } + + MatchRHSPunctuation(tok::r_paren, Loc); + break; + } + case tok::arrow: // postfix-expression: p-e '->' identifier + case tok::period: { // postfix-expression: p-e '.' identifier + tok::TokenKind OpKind = Tok.getKind(); + SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return ExprResult(true); + } + + if (!LHS.isInvalid) + LHS = Actions.ActOnMemberReferenceExpr(LHS.Val, OpLoc, OpKind, + Tok.getLocation(), + *Tok.getIdentifierInfo()); + ConsumeToken(); + break; + } + case tok::plusplus: // postfix-expression: postfix-expression '++' + case tok::minusminus: // postfix-expression: postfix-expression '--' + if (!LHS.isInvalid) + LHS = Actions.ActOnPostfixUnaryOp(Tok.getLocation(), Tok.getKind(), + LHS.Val); + ConsumeToken(); + break; + } + } +} + + +/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. +/// unary-expression: [C99 6.5.3] +/// 'sizeof' unary-expression +/// 'sizeof' '(' type-name ')' +/// [GNU] '__alignof' unary-expression +/// [GNU] '__alignof' '(' type-name ')' +Parser::ExprResult Parser::ParseSizeofAlignofExpression() { + assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)) && + "Not a sizeof/alignof expression!"); + Token OpTok = Tok; + ConsumeToken(); + + // If the operand doesn't start with an '(', it must be an expression. + ExprResult Operand; + if (Tok.isNot(tok::l_paren)) { + Operand = ParseCastExpression(true); + } else { + // If it starts with a '(', we know that it is either a parenthesized + // type-name, or it is a unary-expression that starts with a compound + // literal, or starts with a primary-expression that is a parenthesized + // expression. + ParenParseOption ExprType = CastExpr; + TypeTy *CastTy; + SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; + Operand = ParseParenExpression(ExprType, CastTy, RParenLoc); + + // If ParseParenExpression parsed a '(typename)' sequence only, the this is + // sizeof/alignof a type. Otherwise, it is sizeof/alignof an expression. + if (ExprType == CastExpr) + return Actions.ActOnSizeOfAlignOfTypeExpr(OpTok.getLocation(), + OpTok.is(tok::kw_sizeof), + LParenLoc, CastTy, RParenLoc); + + // If this is a parenthesized expression, it is the start of a + // unary-expression, but doesn't include any postfix pieces. Parse these + // now if present. + Operand = ParsePostfixExpressionSuffix(Operand); + } + + // If we get here, the operand to the sizeof/alignof was an expresion. + if (!Operand.isInvalid) + Operand = Actions.ActOnUnaryOp(OpTok.getLocation(), OpTok.getKind(), + Operand.Val); + return Operand; +} + +/// ParseBuiltinPrimaryExpression +/// +/// primary-expression: [C99 6.5.1] +/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' +/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' +/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' +/// assign-expr ')' +/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [CLANG] '__builtin_overload' '(' expr (',' expr)* ')' +/// +/// [GNU] offsetof-member-designator: +/// [GNU] identifier +/// [GNU] offsetof-member-designator '.' identifier +/// [GNU] offsetof-member-designator '[' expression ']' +/// +Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() { + ExprResult Res(false); + const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); + + tok::TokenKind T = Tok.getKind(); + SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. + + // All of these start with an open paren. + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName()); + return ExprResult(true); + } + + SourceLocation LParenLoc = ConsumeParen(); + // TODO: Build AST. + + switch (T) { + default: assert(0 && "Not a builtin primary expression!"); + case tok::kw___builtin_va_arg: { + ExprResult Expr = ParseAssignmentExpression(); + if (Expr.isInvalid) { + SkipUntil(tok::r_paren); + return Res; + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprResult(true); + + TypeTy *Ty = ParseTypeName(); + + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + return ExprResult(true); + } + Res = Actions.ActOnVAArg(StartLoc, Expr.Val, Ty, ConsumeParen()); + break; + } + case tok::kw___builtin_offsetof: { + SourceLocation TypeLoc = Tok.getLocation(); + TypeTy *Ty = ParseTypeName(); + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprResult(true); + + // We must have at least one identifier here. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return true; + } + + // Keep track of the various subcomponents we see. + llvm::SmallVector Comps; + + Comps.push_back(Action::OffsetOfComponent()); + Comps.back().isBrackets = false; + Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); + Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); + + while (1) { + if (Tok.is(tok::period)) { + // offsetof-member-designator: offsetof-member-designator '.' identifier + Comps.push_back(Action::OffsetOfComponent()); + Comps.back().isBrackets = false; + Comps.back().LocStart = ConsumeToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return true; + } + Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); + Comps.back().LocEnd = ConsumeToken(); + + } else if (Tok.is(tok::l_square)) { + // offsetof-member-designator: offsetof-member-design '[' expression ']' + Comps.push_back(Action::OffsetOfComponent()); + Comps.back().isBrackets = true; + Comps.back().LocStart = ConsumeBracket(); + Res = ParseExpression(); + if (Res.isInvalid) { + SkipUntil(tok::r_paren); + return Res; + } + Comps.back().U.E = Res.Val; + + Comps.back().LocEnd = + MatchRHSPunctuation(tok::r_square, Comps.back().LocStart); + } else if (Tok.is(tok::r_paren)) { + Res = Actions.ActOnBuiltinOffsetOf(StartLoc, TypeLoc, Ty, &Comps[0], + Comps.size(), ConsumeParen()); + break; + } else { + // Error occurred. + return ExprResult(true); + } + } + break; + } + case tok::kw___builtin_choose_expr: { + ExprResult Cond = ParseAssignmentExpression(); + if (Cond.isInvalid) { + SkipUntil(tok::r_paren); + return Cond; + } + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprResult(true); + + ExprResult Expr1 = ParseAssignmentExpression(); + if (Expr1.isInvalid) { + SkipUntil(tok::r_paren); + return Expr1; + } + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprResult(true); + + ExprResult Expr2 = ParseAssignmentExpression(); + if (Expr2.isInvalid) { + SkipUntil(tok::r_paren); + return Expr2; + } + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + return ExprResult(true); + } + Res = Actions.ActOnChooseExpr(StartLoc, Cond.Val, Expr1.Val, Expr2.Val, + ConsumeParen()); + break; + } + case tok::kw___builtin_overload: { + llvm::SmallVector ArgExprs; + llvm::SmallVector CommaLocs; + + // For each iteration through the loop look for assign-expr followed by a + // comma. If there is no comma, break and attempt to match r-paren. + if (Tok.isNot(tok::r_paren)) { + while (1) { + ExprResult ArgExpr = ParseAssignmentExpression(); + if (ArgExpr.isInvalid) { + SkipUntil(tok::r_paren); + return ExprResult(true); + } else + ArgExprs.push_back(ArgExpr.Val); + + if (Tok.isNot(tok::comma)) + break; + // Move to the next argument, remember where the comma was. + CommaLocs.push_back(ConsumeToken()); + } + } + + // Attempt to consume the r-paren + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren); + return ExprResult(true); + } + Res = Actions.ActOnOverloadExpr(&ArgExprs[0], ArgExprs.size(), + &CommaLocs[0], StartLoc, ConsumeParen()); + break; + } + case tok::kw___builtin_types_compatible_p: + TypeTy *Ty1 = ParseTypeName(); + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) + return ExprResult(true); + + TypeTy *Ty2 = ParseTypeName(); + + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + return ExprResult(true); + } + Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1, Ty2, ConsumeParen()); + break; + } + + // These can be followed by postfix-expr pieces because they are + // primary-expressions. + return ParsePostfixExpressionSuffix(Res); +} + +/// ParseParenExpression - This parses the unit that starts with a '(' token, +/// based on what is allowed by ExprType. The actual thing parsed is returned +/// in ExprType. +/// +/// primary-expression: [C99 6.5.1] +/// '(' expression ')' +/// [GNU] '(' compound-statement ')' (if !ParenExprOnly) +/// postfix-expression: [C99 6.5.2] +/// '(' type-name ')' '{' initializer-list '}' +/// '(' type-name ')' '{' initializer-list ',' '}' +/// cast-expression: [C99 6.5.4] +/// '(' type-name ')' cast-expression +/// +Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, + TypeTy *&CastTy, + SourceLocation &RParenLoc) { + assert(Tok.is(tok::l_paren) && "Not a paren expr!"); + SourceLocation OpenLoc = ConsumeParen(); + ExprResult Result(true); + CastTy = 0; + + if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { + Diag(Tok, diag::ext_gnu_statement_expr); + Parser::StmtResult Stmt = ParseCompoundStatement(true); + ExprType = CompoundStmt; + + // If the substmt parsed correctly, build the AST node. + if (!Stmt.isInvalid && Tok.is(tok::r_paren)) + Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.Val, Tok.getLocation()); + + } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) { + // Otherwise, this is a compound literal expression or cast expression. + TypeTy *Ty = ParseTypeName(); + + // Match the ')'. + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, OpenLoc); + + if (Tok.is(tok::l_brace)) { + if (!getLang().C99) // Compound literals don't exist in C90. + Diag(OpenLoc, diag::ext_c99_compound_literal); + Result = ParseInitializer(); + ExprType = CompoundLiteral; + if (!Result.isInvalid) + return Actions.ActOnCompoundLiteral(OpenLoc, Ty, RParenLoc, Result.Val); + } else if (ExprType == CastExpr) { + // Note that this doesn't parse the subsequence cast-expression, it just + // returns the parsed type to the callee. + ExprType = CastExpr; + CastTy = Ty; + return ExprResult(false); + } else { + Diag(Tok, diag::err_expected_lbrace_in_compound_literal); + return ExprResult(true); + } + return Result; + } else { + Result = ParseExpression(); + ExprType = SimpleExpr; + if (!Result.isInvalid && Tok.is(tok::r_paren)) + Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.Val); + } + + // Match the ')'. + if (Result.isInvalid) + SkipUntil(tok::r_paren); + else { + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, OpenLoc); + } + + return Result; +} + +/// ParseStringLiteralExpression - This handles the various token types that +/// form string literals, and also handles string concatenation [C99 5.1.1.2, +/// translation phase #6]. +/// +/// primary-expression: [C99 6.5.1] +/// string-literal +Parser::ExprResult Parser::ParseStringLiteralExpression() { + assert(isTokenStringLiteral() && "Not a string literal!"); + + // String concat. Note that keywords like __func__ and __FUNCTION__ are not + // considered to be strings for concatenation purposes. + llvm::SmallVector StringToks; + + do { + StringToks.push_back(Tok); + ConsumeStringToken(); + } while (isTokenStringLiteral()); + + // Pass the set of string tokens, ready for concatenation, to the actions. + return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); +} diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp new file mode 100644 index 00000000000..6b42fb5b089 --- /dev/null +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -0,0 +1,99 @@ +//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expression parsing implementation for C++. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Parse/Parser.h" +using namespace clang; + +/// ParseCXXCasts - This handles the various ways to cast expressions to another +/// type. +/// +/// postfix-expression: [C++ 5.2p1] +/// 'dynamic_cast' '<' type-name '>' '(' expression ')' +/// 'static_cast' '<' type-name '>' '(' expression ')' +/// 'reinterpret_cast' '<' type-name '>' '(' expression ')' +/// 'const_cast' '<' type-name '>' '(' expression ')' +/// +Parser::ExprResult Parser::ParseCXXCasts() { + tok::TokenKind Kind = Tok.getKind(); + const char *CastName = 0; // For error messages + + switch (Kind) { + default: assert(0 && "Unknown C++ cast!"); abort(); + case tok::kw_const_cast: CastName = "const_cast"; break; + case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; + case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; + case tok::kw_static_cast: CastName = "static_cast"; break; + } + + SourceLocation OpLoc = ConsumeToken(); + SourceLocation LAngleBracketLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) + return ExprResult(true); + + TypeTy *CastTy = ParseTypeName(); + SourceLocation RAngleBracketLoc = Tok.getLocation(); + + if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) { + Diag(LAngleBracketLoc, diag::err_matching, "<"); + return ExprResult(true); + } + + SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, CastName); + return ExprResult(true); + } + + ExprResult Result = ParseSimpleParenExpression(RParenLoc); + + if (!Result.isInvalid) + Result = Actions.ActOnCXXCasts(OpLoc, Kind, + LAngleBracketLoc, CastTy, RAngleBracketLoc, + LParenLoc, Result.Val, RParenLoc); + + return Result; +} + +/// ParseCXXBoolLiteral - This handles the C++ Boolean literals. +/// +/// boolean-literal: [C++ 2.13.5] +/// 'true' +/// 'false' +Parser::ExprResult Parser::ParseCXXBoolLiteral() { + tok::TokenKind Kind = Tok.getKind(); + return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind); +} + +/// ParseThrowExpression - This handles the C++ throw expression. +/// +/// throw-expression: [C++ 15] +/// 'throw' assignment-expression[opt] +Parser::ExprResult Parser::ParseThrowExpression() { + assert(Tok.is(tok::kw_throw) && "Not throw!"); + + ExprResult Expr; + + SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. + // FIXME: Anything that isn't an assignment-expression should bail out now. + if (Tok.is(tok::semi) || Tok.is(tok::r_paren) || Tok.is(tok::colon) || + Tok.is(tok::comma)) + return Actions.ActOnCXXThrow(ThrowLoc); + + Expr = ParseAssignmentExpression(); + if (!Expr.isInvalid) + Expr = Actions.ActOnCXXThrow(ThrowLoc, Expr.Val); + return Expr; +} diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp new file mode 100644 index 00000000000..45cf86e5b44 --- /dev/null +++ b/clang/lib/Parse/ParseInit.cpp @@ -0,0 +1,227 @@ +//===--- ParseInit.cpp - Initializer Parsing ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements initializer parsing as specified by C99 6.7.8. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + + +/// MayBeDesignationStart - Return true if this token might be the start of a +/// designator. +static bool MayBeDesignationStart(tok::TokenKind K) { + switch (K) { + default: return false; + case tok::period: // designator: '.' identifier + case tok::l_square: // designator: array-designator + case tok::identifier: // designation: identifier ':' + return true; + } +} + +/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production +/// checking to see if the token stream starts with a designator. +/// +/// designation: +/// designator-list '=' +/// [GNU] array-designator +/// [GNU] identifier ':' +/// +/// designator-list: +/// designator +/// designator-list designator +/// +/// designator: +/// array-designator +/// '.' identifier +/// +/// array-designator: +/// '[' constant-expression ']' +/// [GNU] '[' constant-expression '...' constant-expression ']' +/// +/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an +/// initializer. We need to consider this case when parsing array designators. +/// +Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() { + // Parse each designator in the designator list until we find an initializer. + while (1) { + switch (Tok.getKind()) { + case tok::equal: + // We read some number (at least one due to the grammar we implemented) + // of designators and found an '=' sign. The following tokens must be + // the initializer. + ConsumeToken(); + return ParseInitializer(); + + default: { + // We read some number (at least one due to the grammar we implemented) + // of designators and found something that isn't an = or an initializer. + // If we have exactly one array designator [TODO CHECK], this is the GNU + // 'designation: array-designator' extension. Otherwise, it is a parse + // error. + SourceLocation Loc = Tok.getLocation(); + ExprResult Init = ParseInitializer(); + if (Init.isInvalid) return Init; + + Diag(Tok, diag::ext_gnu_missing_equal_designator); + return Init; + } + case tok::period: + // designator: '.' identifier + ConsumeToken(); + if (ExpectAndConsume(tok::identifier, diag::err_expected_ident)) + return ExprResult(true); + break; + + case tok::l_square: { + // array-designator: '[' constant-expression ']' + // array-designator: '[' constant-expression '...' constant-expression ']' + // When designation is empty, this can be '[' objc-message-expr ']'. Note + // that we also have the case of [4][foo bar], which is the gnu designator + // extension + objc message send. + SourceLocation StartLoc = ConsumeBracket(); + + // If Objective-C is enabled and this is a typename or other identifier + // receiver, parse this as a message send expression. + if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) { + // FIXME: Emit ext_gnu_missing_equal_designator for inits like + // [4][foo bar]. + IdentifierInfo *Name = Tok.getIdentifierInfo(); + ConsumeToken(); + ExprResult R = ParseObjCMessageExpressionBody(StartLoc, Name, 0); + return ParsePostfixExpressionSuffix(R); + } + + // Note that we parse this as an assignment expression, not a constant + // expression (allowing *=, =, etc) to handle the objc case. Sema needs + // to validate that the expression is a constant. + ExprResult Idx = ParseAssignmentExpression(); + if (Idx.isInvalid) { + SkipUntil(tok::r_square); + return Idx; + } + + // Given an expression, we could either have a designator (if the next + // tokens are '...' or ']' or an objc message send. If this is an objc + // message send, handle it now. + if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && + Tok.isNot(tok::r_square)) { + // FIXME: Emit ext_gnu_missing_equal_designator for inits like + // [4][foo bar]. + ExprResult R = ParseObjCMessageExpressionBody(StartLoc, 0, Idx.Val); + return ParsePostfixExpressionSuffix(R); + } + + // Handle the gnu array range extension. + if (Tok.is(tok::ellipsis)) { + Diag(Tok, diag::ext_gnu_array_range); + ConsumeToken(); + + ExprResult RHS = ParseConstantExpression(); + if (RHS.isInvalid) { + SkipUntil(tok::r_square); + return RHS; + } + } + + MatchRHSPunctuation(tok::r_square, StartLoc); + break; + } + case tok::identifier: { + // Due to the GNU "designation: identifier ':'" extension, we don't know + // whether something starting with an identifier is an + // assignment-expression or if it is an old-style structure field + // designator. + // TODO: Check that this is the first designator. + Token Ident = Tok; + ConsumeToken(); + + // If this is the gross GNU extension, handle it now. + if (Tok.is(tok::colon)) { + Diag(Ident, diag::ext_gnu_old_style_field_designator); + ConsumeToken(); + return ParseInitializer(); + } + + // Otherwise, we just consumed the first token of an expression. Parse + // the rest of it now. + return ParseAssignmentExprWithLeadingIdentifier(Ident); + } + } + } +} + + +/// ParseInitializer +/// initializer: [C99 6.7.8] +/// assignment-expression +/// '{' initializer-list '}' +/// '{' initializer-list ',' '}' +/// [GNU] '{' '}' +/// +/// initializer-list: +/// designation[opt] initializer +/// initializer-list ',' designation[opt] initializer +/// +Parser::ExprResult Parser::ParseInitializer() { + if (Tok.isNot(tok::l_brace)) + return ParseAssignmentExpression(); + + SourceLocation LBraceLoc = ConsumeBrace(); + + // We support empty initializers, but tell the user that they aren't using + // C99-clean code. + if (Tok.is(tok::r_brace)) { + Diag(LBraceLoc, diag::ext_gnu_empty_initializer); + // Match the '}'. + return Actions.ActOnInitList(LBraceLoc, 0, 0, ConsumeBrace()); + } + llvm::SmallVector InitExprs; + bool InitExprsOk = true; + + while (1) { + // Parse: designation[opt] initializer + + // If we know that this cannot be a designation, just parse the nested + // initializer directly. + ExprResult SubElt; + if (!MayBeDesignationStart(Tok.getKind())) + SubElt = ParseInitializer(); + else + SubElt = ParseInitializerWithPotentialDesignator(); + + // If we couldn't parse the subelement, bail out. + if (SubElt.isInvalid) { + InitExprsOk = false; + SkipUntil(tok::r_brace, false, true); + break; + } else + InitExprs.push_back(SubElt.Val); + + // If we don't have a comma continued list, we're done. + if (Tok.isNot(tok::comma)) break; + + // FIXME: save comma locations. + ConsumeToken(); + + // Handle trailing comma. + if (Tok.is(tok::r_brace)) break; + } + if (InitExprsOk && Tok.is(tok::r_brace)) + return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(), + ConsumeBrace()); + // Match the '}'. + MatchRHSPunctuation(tok::r_brace, LBraceLoc); + return ExprResult(true); // an error occurred. +} + diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp new file mode 100644 index 00000000000..77d2adbd320 --- /dev/null +++ b/clang/lib/Parse/ParseObjc.cpp @@ -0,0 +1,1578 @@ +//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Objective-C portions of the Parser interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallVector.h" +using namespace clang; + + +/// ParseExternalDeclaration: +/// external-declaration: [C99 6.9] +/// [OBJC] objc-class-definition +/// [OBJC] objc-class-declaration +/// [OBJC] objc-alias-declaration +/// [OBJC] objc-protocol-definition +/// [OBJC] objc-method-definition +/// [OBJC] '@' 'end' +Parser::DeclTy *Parser::ParseObjCAtDirectives() { + SourceLocation AtLoc = ConsumeToken(); // the "@" + + switch (Tok.getObjCKeywordID()) { + case tok::objc_class: + return ParseObjCAtClassDeclaration(AtLoc); + case tok::objc_interface: + return ParseObjCAtInterfaceDeclaration(AtLoc); + case tok::objc_protocol: + return ParseObjCAtProtocolDeclaration(AtLoc); + case tok::objc_implementation: + return ParseObjCAtImplementationDeclaration(AtLoc); + case tok::objc_end: + return ParseObjCAtEndDeclaration(AtLoc); + case tok::objc_compatibility_alias: + return ParseObjCAtAliasDeclaration(AtLoc); + case tok::objc_synthesize: + return ParseObjCPropertySynthesize(AtLoc); + case tok::objc_dynamic: + return ParseObjCPropertyDynamic(AtLoc); + default: + Diag(AtLoc, diag::err_unexpected_at); + SkipUntil(tok::semi); + return 0; + } +} + +/// +/// objc-class-declaration: +/// '@' 'class' identifier-list ';' +/// +Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { + ConsumeToken(); // the identifier "class" + llvm::SmallVector ClassNames; + + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return 0; + } + ClassNames.push_back(Tok.getIdentifierInfo()); + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } + + // Consume the ';'. + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) + return 0; + + return Actions.ActOnForwardClassDeclaration(atLoc, + &ClassNames[0], ClassNames.size()); +} + +/// +/// objc-interface: +/// objc-class-interface-attributes[opt] objc-class-interface +/// objc-category-interface +/// +/// objc-class-interface: +/// '@' 'interface' identifier objc-superclass[opt] +/// objc-protocol-refs[opt] +/// objc-class-instance-variables[opt] +/// objc-interface-decl-list +/// @end +/// +/// objc-category-interface: +/// '@' 'interface' identifier '(' identifier[opt] ')' +/// objc-protocol-refs[opt] +/// objc-interface-decl-list +/// @end +/// +/// objc-superclass: +/// ':' identifier +/// +/// objc-class-interface-attributes: +/// __attribute__((visibility("default"))) +/// __attribute__((visibility("hidden"))) +/// __attribute__((deprecated)) +/// __attribute__((unavailable)) +/// __attribute__((objc_exception)) - used by NSException on 64-bit +/// +Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( + SourceLocation atLoc, AttributeList *attrList) { + assert(Tok.isObjCAtKeyword(tok::objc_interface) && + "ParseObjCAtInterfaceDeclaration(): Expected @interface"); + ConsumeToken(); // the "interface" identifier + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing class or category name. + return 0; + } + // We have a class or category name - consume it. + IdentifierInfo *nameId = Tok.getIdentifierInfo(); + SourceLocation nameLoc = ConsumeToken(); + + if (Tok.is(tok::l_paren)) { // we have a category. + SourceLocation lparenLoc = ConsumeParen(); + SourceLocation categoryLoc, rparenLoc; + IdentifierInfo *categoryId = 0; + llvm::SmallVector ProtocolRefs; + + // For ObjC2, the category name is optional (not an error). + if (Tok.is(tok::identifier)) { + categoryId = Tok.getIdentifierInfo(); + categoryLoc = ConsumeToken(); + } else if (!getLang().ObjC2) { + Diag(Tok, diag::err_expected_ident); // missing category name. + return 0; + } + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren, false); // don't stop at ';' + return 0; + } + rparenLoc = ConsumeParen(); + SourceLocation endProtoLoc; + // Next, we need to check for any protocol references. + if (Tok.is(tok::less)) { + if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc)) + return 0; + } + if (attrList) // categories don't support attributes. + Diag(Tok, diag::err_objc_no_attributes_on_category); + + DeclTy *CategoryType = Actions.ActOnStartCategoryInterface(atLoc, + nameId, nameLoc, categoryId, categoryLoc, + &ProtocolRefs[0], ProtocolRefs.size(), + endProtoLoc); + + ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); + + // The @ sign was already consumed by ParseObjCInterfaceDeclList(). + if (Tok.isObjCAtKeyword(tok::objc_end)) { + ConsumeToken(); // the "end" identifier + return CategoryType; + } + Diag(Tok, diag::err_objc_missing_end); + return 0; + } + // Parse a class interface. + IdentifierInfo *superClassId = 0; + SourceLocation superClassLoc; + + if (Tok.is(tok::colon)) { // a super class is specified. + ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing super class name. + return 0; + } + superClassId = Tok.getIdentifierInfo(); + superClassLoc = ConsumeToken(); + } + // Next, we need to check for any protocol references. + llvm::SmallVector ProtocolRefs; + SourceLocation endProtoLoc; + if (Tok.is(tok::less)) { + if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc)) + return 0; + } + DeclTy *ClsType = Actions.ActOnStartClassInterface( + atLoc, nameId, nameLoc, + superClassId, superClassLoc, &ProtocolRefs[0], + ProtocolRefs.size(), endProtoLoc, attrList); + + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(ClsType, atLoc); + + ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); + + // The @ sign was already consumed by ParseObjCInterfaceDeclList(). + if (Tok.isObjCAtKeyword(tok::objc_end)) { + ConsumeToken(); // the "end" identifier + return ClsType; + } + Diag(Tok, diag::err_objc_missing_end); + return 0; +} + +/// objc-interface-decl-list: +/// empty +/// objc-interface-decl-list objc-property-decl [OBJC2] +/// objc-interface-decl-list objc-method-requirement [OBJC2] +/// objc-interface-decl-list objc-method-proto ';' +/// objc-interface-decl-list declaration +/// objc-interface-decl-list ';' +/// +/// objc-method-requirement: [OBJC2] +/// @required +/// @optional +/// +void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl, + tok::ObjCKeywordKind contextKey) { + llvm::SmallVector allMethods; + llvm::SmallVector allProperties; + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; + SourceLocation AtEndLoc; + + while (1) { + if (Tok.is(tok::at)) { + SourceLocation AtLoc = ConsumeToken(); // the "@" + tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID(); + + if (ocKind == tok::objc_end) { // terminate list + AtEndLoc = AtLoc; + break; + } else if (ocKind == tok::objc_required) { // protocols only + ConsumeToken(); + MethodImplKind = ocKind; + if (contextKey != tok::objc_protocol) + Diag(AtLoc, diag::err_objc_protocol_required); + } else if (ocKind == tok::objc_optional) { // protocols only + ConsumeToken(); + MethodImplKind = ocKind; + if (contextKey != tok::objc_protocol) + Diag(AtLoc, diag::err_objc_protocol_optional); + } else if (ocKind == tok::objc_property) { + allProperties.push_back(ParseObjCPropertyDecl(interfaceDecl, AtLoc)); + continue; + } else { + Diag(Tok, diag::err_objc_illegal_interface_qual); + ConsumeToken(); + } + } + if (Tok.is(tok::minus) || Tok.is(tok::plus)) { + DeclTy *methodPrototype = + ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); + allMethods.push_back(methodPrototype); + // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for + // method definitions. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after,"method proto"); + continue; + } + else if (Tok.is(tok::at)) + continue; + + if (Tok.is(tok::semi)) + ConsumeToken(); + else if (Tok.is(tok::eof)) + break; + else { + // FIXME: as the name implies, this rule allows function definitions. + // We could pass a flag or check for functions during semantic analysis. + ParseDeclarationOrFunctionDefinition(); + } + } + /// Insert collected methods declarations into the @interface object. + Actions.ActOnAtEnd(AtEndLoc, interfaceDecl, &allMethods[0], allMethods.size(), + &allProperties[0], allProperties.size()); +} + +/// Parse property attribute declarations. +/// +/// property-attr-decl: '(' property-attrlist ')' +/// property-attrlist: +/// property-attribute +/// property-attrlist ',' property-attribute +/// property-attribute: +/// getter '=' identifier +/// setter '=' identifier ':' +/// readonly +/// readwrite +/// assign +/// retain +/// copy +/// nonatomic +/// +void Parser::ParseObjCPropertyAttribute (ObjCDeclSpec &DS) { + SourceLocation loc = ConsumeParen(); // consume '(' + while (isObjCPropertyAttribute()) { + const IdentifierInfo *II = Tok.getIdentifierInfo(); + // getter/setter require extra treatment. + if (II == ObjCPropertyAttrs[objc_getter] || + II == ObjCPropertyAttrs[objc_setter]) { + // skip getter/setter part. + SourceLocation loc = ConsumeToken(); + if (Tok.is(tok::equal)) { + loc = ConsumeToken(); + if (Tok.is(tok::identifier)) { + if (II == ObjCPropertyAttrs[objc_setter]) { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); + DS.setSetterName(Tok.getIdentifierInfo()); + loc = ConsumeToken(); // consume method name + if (Tok.isNot(tok::colon)) { + Diag(loc, diag::err_expected_colon); + SkipUntil(tok::r_paren,true,true); + break; + } + } + else { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); + DS.setGetterName(Tok.getIdentifierInfo()); + } + } + else { + Diag(loc, diag::err_expected_ident); + SkipUntil(tok::r_paren,true,true); + break; + } + } + else { + Diag(loc, diag::err_objc_expected_equal); + SkipUntil(tok::r_paren,true,true); + break; + } + } + + else if (II == ObjCPropertyAttrs[objc_readonly]) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly); + else if (II == ObjCPropertyAttrs[objc_assign]) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign); + else if (II == ObjCPropertyAttrs[objc_readwrite]) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite); + else if (II == ObjCPropertyAttrs[objc_retain]) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain); + else if (II == ObjCPropertyAttrs[objc_copy]) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy); + else if (II == ObjCPropertyAttrs[objc_nonatomic]) + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic); + + ConsumeToken(); // consume last attribute token + if (Tok.is(tok::comma)) { + loc = ConsumeToken(); + continue; + } + if (Tok.is(tok::r_paren)) + break; + Diag(loc, diag::err_expected_rparen); + SkipUntil(tok::semi); + return; + } + if (Tok.is(tok::r_paren)) + ConsumeParen(); + else { + Diag(loc, diag::err_objc_expected_property_attr); + SkipUntil(tok::r_paren); // recover from error inside attribute list + } +} + +/// Main routine to parse property declaration. +/// +/// @property property-attr-decl[opt] property-component-decl ';' +/// +Parser::DeclTy *Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl, + SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_property) && + "ParseObjCPropertyDecl(): Expected @property"); + ObjCDeclSpec DS; + ConsumeToken(); // the "property" identifier + // Parse property attribute list, if any. + if (Tok.is(tok::l_paren)) { + // property has attribute list. + ParseObjCPropertyAttribute(DS); + } + // Parse declaration portion of @property. + llvm::SmallVector PropertyDecls; + ParseStructDeclaration(interfaceDecl, PropertyDecls); + if (Tok.is(tok::semi)) + ConsumeToken(); + else { + Diag(Tok, diag::err_expected_semi_decl_list); + SkipUntil(tok::r_brace, true, true); + } + return Actions.ActOnAddObjCProperties(AtLoc, + &PropertyDecls[0], PropertyDecls.size(), DS); +} + +/// objc-method-proto: +/// objc-instance-method objc-method-decl objc-method-attributes[opt] +/// objc-class-method objc-method-decl objc-method-attributes[opt] +/// +/// objc-instance-method: '-' +/// objc-class-method: '+' +/// +/// objc-method-attributes: [OBJC2] +/// __attribute__((deprecated)) +/// +Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl, + tok::ObjCKeywordKind MethodImplKind) { + assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); + + tok::TokenKind methodType = Tok.getKind(); + SourceLocation mLoc = ConsumeToken(); + + DeclTy *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl, MethodImplKind); + // Since this rule is used for both method declarations and definitions, + // the caller is (optionally) responsible for consuming the ';'. + return MDecl; +} + +/// objc-selector: +/// identifier +/// one of +/// enum struct union if else while do for switch case default +/// break continue return goto asm sizeof typeof __alignof +/// unsigned long const short volatile signed restrict _Complex +/// in out inout bycopy byref oneway int char float double void _Bool +/// +IdentifierInfo *Parser::ParseObjCSelector(SourceLocation &SelectorLoc) { + switch (Tok.getKind()) { + default: + return 0; + case tok::identifier: + case tok::kw_typeof: + case tok::kw___alignof: + case tok::kw_auto: + case tok::kw_break: + case tok::kw_case: + case tok::kw_char: + case tok::kw_const: + case tok::kw_continue: + case tok::kw_default: + case tok::kw_do: + case tok::kw_double: + case tok::kw_else: + case tok::kw_enum: + case tok::kw_extern: + case tok::kw_float: + case tok::kw_for: + case tok::kw_goto: + case tok::kw_if: + case tok::kw_inline: + case tok::kw_int: + case tok::kw_long: + case tok::kw_register: + case tok::kw_restrict: + case tok::kw_return: + case tok::kw_short: + case tok::kw_signed: + case tok::kw_sizeof: + case tok::kw_static: + case tok::kw_struct: + case tok::kw_switch: + case tok::kw_typedef: + case tok::kw_union: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_volatile: + case tok::kw_while: + case tok::kw_bool: + case tok::kw__Bool: + case tok::kw__Complex: + IdentifierInfo *II = Tok.getIdentifierInfo(); + SelectorLoc = ConsumeToken(); + return II; + } +} + +/// property-attrlist: one of +/// readonly getter setter assign retain copy nonatomic +/// +bool Parser::isObjCPropertyAttribute() { + if (Tok.is(tok::identifier)) { + const IdentifierInfo *II = Tok.getIdentifierInfo(); + for (unsigned i = 0; i < objc_NumAttrs; ++i) + if (II == ObjCPropertyAttrs[i]) return true; + } + return false; +} + +/// objc-for-collection-in: 'in' +/// +bool Parser::isTokIdentifier_in() const { + // FIXME: May have to do additional look-ahead to only allow for + // valid tokens following an 'in'; such as an identifier, unary operators, + // '[' etc. + return (getLang().ObjC2 && Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == ObjCForCollectionInKW); +} + +/// ParseObjCTypeQualifierList - This routine parses the objective-c's type +/// qualifier list and builds their bitmask representation in the input +/// argument. +/// +/// objc-type-qualifiers: +/// objc-type-qualifier +/// objc-type-qualifiers objc-type-qualifier +/// +void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { + while (1) { + if (Tok.isNot(tok::identifier)) + return; + + const IdentifierInfo *II = Tok.getIdentifierInfo(); + for (unsigned i = 0; i != objc_NumQuals; ++i) { + if (II != ObjCTypeQuals[i]) + continue; + + ObjCDeclSpec::ObjCDeclQualifier Qual; + switch (i) { + default: assert(0 && "Unknown decl qualifier"); + case objc_in: Qual = ObjCDeclSpec::DQ_In; break; + case objc_out: Qual = ObjCDeclSpec::DQ_Out; break; + case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break; + case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break; + case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break; + case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break; + } + DS.setObjCDeclQualifier(Qual); + ConsumeToken(); + II = 0; + break; + } + + // If this wasn't a recognized qualifier, bail out. + if (II) return; + } +} + +/// objc-type-name: +/// '(' objc-type-qualifiers[opt] type-name ')' +/// '(' objc-type-qualifiers[opt] ')' +/// +Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { + assert(Tok.is(tok::l_paren) && "expected ("); + + SourceLocation LParenLoc = ConsumeParen(), RParenLoc; + TypeTy *Ty = 0; + + // Parse type qualifiers, in, inout, etc. + ParseObjCTypeQualifierList(DS); + + if (isTypeSpecifierQualifier()) { + Ty = ParseTypeName(); + // FIXME: back when Sema support is in place... + // assert(Ty && "Parser::ParseObjCTypeName(): missing type"); + } + if (Tok.isNot(tok::r_paren)) { + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return 0; // FIXME: decide how we want to handle this error... + } + RParenLoc = ConsumeParen(); + return Ty; +} + +/// objc-method-decl: +/// objc-selector +/// objc-keyword-selector objc-parmlist[opt] +/// objc-type-name objc-selector +/// objc-type-name objc-keyword-selector objc-parmlist[opt] +/// +/// objc-keyword-selector: +/// objc-keyword-decl +/// objc-keyword-selector objc-keyword-decl +/// +/// objc-keyword-decl: +/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier +/// objc-selector ':' objc-keyword-attributes[opt] identifier +/// ':' objc-type-name objc-keyword-attributes[opt] identifier +/// ':' objc-keyword-attributes[opt] identifier +/// +/// objc-parmlist: +/// objc-parms objc-ellipsis[opt] +/// +/// objc-parms: +/// objc-parms , parameter-declaration +/// +/// objc-ellipsis: +/// , ... +/// +/// objc-keyword-attributes: [OBJC2] +/// __attribute__((unused)) +/// +Parser::DeclTy *Parser::ParseObjCMethodDecl(SourceLocation mLoc, + tok::TokenKind mType, + DeclTy *IDecl, + tok::ObjCKeywordKind MethodImplKind) +{ + // Parse the return type. + TypeTy *ReturnType = 0; + ObjCDeclSpec DSRet; + if (Tok.is(tok::l_paren)) + ReturnType = ParseObjCTypeName(DSRet); + SourceLocation selLoc; + IdentifierInfo *SelIdent = ParseObjCSelector(selLoc); + if (Tok.isNot(tok::colon)) { + if (!SelIdent) { + Diag(Tok, diag::err_expected_ident); // missing selector name. + // FIXME: this creates a unary selector with a null identifier, is this + // ok?? Maybe we should skip to the next semicolon or something. + } + + // If attributes exist after the method, parse them. + AttributeList *MethodAttrs = 0; + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + MethodAttrs = ParseAttributes(); + + Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); + return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + mType, IDecl, DSRet, ReturnType, Sel, + 0, 0, 0, MethodAttrs, MethodImplKind); + } + + llvm::SmallVector KeyIdents; + llvm::SmallVector KeyTypes; + llvm::SmallVector ArgTypeQuals; + llvm::SmallVector ArgNames; + + Action::TypeTy *TypeInfo; + while (1) { + KeyIdents.push_back(SelIdent); + + // Each iteration parses a single keyword argument. + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon); + break; + } + ConsumeToken(); // Eat the ':'. + ObjCDeclSpec DSType; + if (Tok.is(tok::l_paren)) { // Parse the argument type. + TypeInfo = ParseObjCTypeName(DSType); + } + else + TypeInfo = 0; + KeyTypes.push_back(TypeInfo); + ArgTypeQuals.push_back(DSType); + + // If attributes exist before the argument name, parse them. + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + ParseAttributes(); // FIXME: pass attributes through. + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing argument name. + break; + } + ArgNames.push_back(Tok.getIdentifierInfo()); + ConsumeToken(); // Eat the identifier. + + // Check for another keyword selector. + SourceLocation Loc; + SelIdent = ParseObjCSelector(Loc); + if (!SelIdent && Tok.isNot(tok::colon)) + break; + // We have a selector or a colon, continue parsing. + } + + bool isVariadic = false; + + // Parse the (optional) parameter list. + while (Tok.is(tok::comma)) { + ConsumeToken(); + if (Tok.is(tok::ellipsis)) { + isVariadic = true; + ConsumeToken(); + break; + } + // FIXME: implement this... + // Parse the c-style argument declaration-specifier. + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + // Parse the declarator. + Declarator ParmDecl(DS, Declarator::PrototypeContext); + ParseDeclarator(ParmDecl); + } + + // FIXME: Add support for optional parmameter list... + // If attributes exist after the method, parse them. + AttributeList *MethodAttrs = 0; + if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) + MethodAttrs = ParseAttributes(); + + Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), + &KeyIdents[0]); + return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + mType, IDecl, DSRet, ReturnType, Sel, + &ArgTypeQuals[0], &KeyTypes[0], + &ArgNames[0], MethodAttrs, + MethodImplKind, isVariadic); +} + +/// CmpProtocolVals - Comparison predicate for sorting protocols. +static bool CmpProtocolVals(const IdentifierInfo* const& lhs, + const IdentifierInfo* const& rhs) { + return strcmp(lhs->getName(), rhs->getName()) < 0; +} + +/// objc-protocol-refs: +/// '<' identifier-list '>' +/// +bool Parser::ParseObjCProtocolReferences( + llvm::SmallVectorImpl &ProtocolRefs, SourceLocation &endLoc) +{ + assert(Tok.is(tok::less) && "expected <"); + + ConsumeToken(); // the "<" + + while (1) { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::greater); + return true; + } + ProtocolRefs.push_back(Tok.getIdentifierInfo()); + ConsumeToken(); + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); + } + + // Sort protocols, keyed by name. + // Later on, we remove duplicates. + std::stable_sort(ProtocolRefs.begin(), ProtocolRefs.end(), CmpProtocolVals); + + // Make protocol names unique. + ProtocolRefs.erase(std::unique(ProtocolRefs.begin(), ProtocolRefs.end()), + ProtocolRefs.end()); + // Consume the '>'. + if (Tok.is(tok::greater)) { + endLoc = ConsumeAnyToken(); + return false; + } + Diag(Tok, diag::err_expected_greater); + return true; +} + +/// objc-class-instance-variables: +/// '{' objc-instance-variable-decl-list[opt] '}' +/// +/// objc-instance-variable-decl-list: +/// objc-visibility-spec +/// objc-instance-variable-decl ';' +/// ';' +/// objc-instance-variable-decl-list objc-visibility-spec +/// objc-instance-variable-decl-list objc-instance-variable-decl ';' +/// objc-instance-variable-decl-list ';' +/// +/// objc-visibility-spec: +/// @private +/// @protected +/// @public +/// @package [OBJC2] +/// +/// objc-instance-variable-decl: +/// struct-declaration +/// +void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, + SourceLocation atLoc) { + assert(Tok.is(tok::l_brace) && "expected {"); + llvm::SmallVector IvarDecls; + llvm::SmallVector AllIvarDecls; + llvm::SmallVector AllVisibilities; + + SourceLocation LBraceLoc = ConsumeBrace(); // the "{" + + tok::ObjCKeywordKind visibility = tok::objc_private; + // While we still have something to read, read the instance variables. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // Each iteration of this loop reads one objc-instance-variable-decl. + + // Check for extraneous top-level semicolon. + if (Tok.is(tok::semi)) { + Diag(Tok, diag::ext_extra_struct_semi); + ConsumeToken(); + continue; + } + // Set the default visibility to private. + if (Tok.is(tok::at)) { // parse objc-visibility-spec + ConsumeToken(); // eat the @ sign + switch (Tok.getObjCKeywordID()) { + case tok::objc_private: + case tok::objc_public: + case tok::objc_protected: + case tok::objc_package: + visibility = Tok.getObjCKeywordID(); + ConsumeToken(); + continue; + default: + Diag(Tok, diag::err_objc_illegal_visibility_spec); + ConsumeToken(); + continue; + } + } + ParseStructDeclaration(interfaceDecl, IvarDecls); + for (unsigned i = 0; i < IvarDecls.size(); i++) { + AllIvarDecls.push_back(IvarDecls[i]); + AllVisibilities.push_back(visibility); + } + IvarDecls.clear(); + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else if (Tok.is(tok::r_brace)) { + Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list); + break; + } else { + Diag(Tok, diag::err_expected_semi_decl_list); + // Skip to end of block or statement + SkipUntil(tok::r_brace, true, true); + } + } + SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + // Call ActOnFields() even if we don't have any decls. This is useful + // for code rewriting tools that need to be aware of the empty list. + Actions.ActOnFields(CurScope, atLoc, interfaceDecl, + &AllIvarDecls[0], AllIvarDecls.size(), + LBraceLoc, RBraceLoc, &AllVisibilities[0]); + return; +} + +/// objc-protocol-declaration: +/// objc-protocol-definition +/// objc-protocol-forward-reference +/// +/// objc-protocol-definition: +/// @protocol identifier +/// objc-protocol-refs[opt] +/// objc-interface-decl-list +/// @end +/// +/// objc-protocol-forward-reference: +/// @protocol identifier-list ';' +/// +/// "@protocol identifier ;" should be resolved as "@protocol +/// identifier-list ;": objc-interface-decl-list may not start with a +/// semicolon in the first alternative if objc-protocol-refs are omitted. + +Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_protocol) && + "ParseObjCAtProtocolDeclaration(): Expected @protocol"); + ConsumeToken(); // the "protocol" identifier + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing protocol name. + return 0; + } + // Save the protocol name, then consume it. + IdentifierInfo *protocolName = Tok.getIdentifierInfo(); + SourceLocation nameLoc = ConsumeToken(); + + llvm::SmallVector ProtocolRefs; + if (Tok.is(tok::semi)) { // forward declaration of one protocol. + ConsumeToken(); + ProtocolRefs.push_back(protocolName); + } + if (Tok.is(tok::comma)) { // list of forward declarations. + // Parse the list of forward declarations. + ProtocolRefs.push_back(protocolName); + + while (1) { + ConsumeToken(); // the ',' + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return 0; + } + ProtocolRefs.push_back(Tok.getIdentifierInfo()); + ConsumeToken(); // the identifier + + if (Tok.isNot(tok::comma)) + break; + } + // Consume the ';'. + if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) + return 0; + } + if (ProtocolRefs.size() > 0) + return Actions.ActOnForwardProtocolDeclaration(AtLoc, + &ProtocolRefs[0], + ProtocolRefs.size()); + // Last, and definitely not least, parse a protocol declaration. + SourceLocation endProtoLoc; + if (Tok.is(tok::less)) { + if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc)) + return 0; + } + + DeclTy *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, + protocolName, nameLoc, + &ProtocolRefs[0], + ProtocolRefs.size(), endProtoLoc); + ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); + + // The @ sign was already consumed by ParseObjCInterfaceDeclList(). + if (Tok.isObjCAtKeyword(tok::objc_end)) { + ConsumeToken(); // the "end" identifier + return ProtoType; + } + Diag(Tok, diag::err_objc_missing_end); + return 0; +} + +/// objc-implementation: +/// objc-class-implementation-prologue +/// objc-category-implementation-prologue +/// +/// objc-class-implementation-prologue: +/// @implementation identifier objc-superclass[opt] +/// objc-class-instance-variables[opt] +/// +/// objc-category-implementation-prologue: +/// @implementation identifier ( identifier ) + +Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration( + SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_implementation) && + "ParseObjCAtImplementationDeclaration(): Expected @implementation"); + ConsumeToken(); // the "implementation" identifier + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing class or category name. + return 0; + } + // We have a class or category name - consume it. + IdentifierInfo *nameId = Tok.getIdentifierInfo(); + SourceLocation nameLoc = ConsumeToken(); // consume class or category name + + if (Tok.is(tok::l_paren)) { + // we have a category implementation. + SourceLocation lparenLoc = ConsumeParen(); + SourceLocation categoryLoc, rparenLoc; + IdentifierInfo *categoryId = 0; + + if (Tok.is(tok::identifier)) { + categoryId = Tok.getIdentifierInfo(); + categoryLoc = ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_ident); // missing category name. + return 0; + } + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + SkipUntil(tok::r_paren, false); // don't stop at ';' + return 0; + } + rparenLoc = ConsumeParen(); + DeclTy *ImplCatType = Actions.ActOnStartCategoryImplementation( + atLoc, nameId, nameLoc, categoryId, + categoryLoc); + ObjCImpDecl = ImplCatType; + return 0; + } + // We have a class implementation + SourceLocation superClassLoc; + IdentifierInfo *superClassId = 0; + if (Tok.is(tok::colon)) { + // We have a super class + ConsumeToken(); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); // missing super class name. + return 0; + } + superClassId = Tok.getIdentifierInfo(); + superClassLoc = ConsumeToken(); // Consume super class name + } + DeclTy *ImplClsType = Actions.ActOnStartClassImplementation( + atLoc, nameId, nameLoc, + superClassId, superClassLoc); + + if (Tok.is(tok::l_brace)) // we have ivars + ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); + ObjCImpDecl = ImplClsType; + + return 0; +} + +Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_end) && + "ParseObjCAtEndDeclaration(): Expected @end"); + ConsumeToken(); // the "end" identifier + if (ObjCImpDecl) + Actions.ActOnAtEnd(atLoc, ObjCImpDecl); + else + Diag(atLoc, diag::warn_expected_implementation); // missing @implementation + return ObjCImpDecl; +} + +/// compatibility-alias-decl: +/// @compatibility_alias alias-name class-name ';' +/// +Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) && + "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias"); + ConsumeToken(); // consume compatibility_alias + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return 0; + } + IdentifierInfo *aliasId = Tok.getIdentifierInfo(); + SourceLocation aliasLoc = ConsumeToken(); // consume alias-name + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return 0; + } + IdentifierInfo *classId = Tok.getIdentifierInfo(); + SourceLocation classLoc = ConsumeToken(); // consume class-name; + if (Tok.isNot(tok::semi)) { + Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias"); + return 0; + } + DeclTy *ClsType = Actions.ActOnCompatiblityAlias(atLoc, + aliasId, aliasLoc, + classId, classLoc); + return ClsType; +} + +/// property-synthesis: +/// @synthesize property-ivar-list ';' +/// +/// property-ivar-list: +/// property-ivar +/// property-ivar-list ',' property-ivar +/// +/// property-ivar: +/// identifier +/// identifier '=' identifier +/// +Parser::DeclTy *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && + "ParseObjCPropertyDynamic(): Expected '@synthesize'"); + SourceLocation loc = ConsumeToken(); // consume dynamic + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return 0; + } + while (Tok.is(tok::identifier)) { + ConsumeToken(); // consume property name + if (Tok.is(tok::equal)) { + // property '=' ivar-name + ConsumeToken(); // consume '=' + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + break; + } + ConsumeToken(); // consume ivar-name + } + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // consume ',' + } + if (Tok.isNot(tok::semi)) + Diag(Tok, diag::err_expected_semi_after, "@synthesize"); + return 0; +} + +/// property-dynamic: +/// @dynamic property-list +/// +/// property-list: +/// identifier +/// property-list ',' identifier +/// +Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && + "ParseObjCPropertyDynamic(): Expected '@dynamic'"); + SourceLocation loc = ConsumeToken(); // consume dynamic + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return 0; + } + while (Tok.is(tok::identifier)) { + ConsumeToken(); // consume property name + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); // consume ',' + } + if (Tok.isNot(tok::semi)) + Diag(Tok, diag::err_expected_semi_after, "@dynamic"); + return 0; +} + +/// objc-throw-statement: +/// throw expression[opt]; +/// +Parser::StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { + ExprResult Res; + ConsumeToken(); // consume throw + if (Tok.isNot(tok::semi)) { + Res = ParseExpression(); + if (Res.isInvalid) { + SkipUntil(tok::semi); + return true; + } + } + ConsumeToken(); // consume ';' + return Actions.ActOnObjCAtThrowStmt(atLoc, Res.Val); +} + +/// objc-synchronized-statement: +/// @synchronized '(' expression ')' compound-statement +/// +Parser::StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { + ConsumeToken(); // consume synchronized + if (Tok.isNot(tok::l_paren)) { + Diag (Tok, diag::err_expected_lparen_after, "@synchronized"); + return true; + } + ConsumeParen(); // '(' + ExprResult Res = ParseExpression(); + if (Res.isInvalid) { + SkipUntil(tok::semi); + return true; + } + if (Tok.isNot(tok::r_paren)) { + Diag (Tok, diag::err_expected_lbrace); + return true; + } + ConsumeParen(); // ')' + if (Tok.isNot(tok::l_brace)) { + Diag (Tok, diag::err_expected_lbrace); + return true; + } + StmtResult SynchBody = ParseCompoundStatementBody(); + if (SynchBody.isInvalid) + SynchBody = Actions.ActOnNullStmt(Tok.getLocation()); + return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.Val, SynchBody.Val); +} + +/// objc-try-catch-statement: +/// @try compound-statement objc-catch-list[opt] +/// @try compound-statement objc-catch-list[opt] @finally compound-statement +/// +/// objc-catch-list: +/// @catch ( parameter-declaration ) compound-statement +/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement +/// catch-parameter-declaration: +/// parameter-declaration +/// '...' [OBJC2] +/// +Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { + bool catch_or_finally_seen = false; + + ConsumeToken(); // consume try + if (Tok.isNot(tok::l_brace)) { + Diag (Tok, diag::err_expected_lbrace); + return true; + } + StmtResult CatchStmts; + StmtResult FinallyStmt; + StmtResult TryBody = ParseCompoundStatementBody(); + if (TryBody.isInvalid) + TryBody = Actions.ActOnNullStmt(Tok.getLocation()); + + while (Tok.is(tok::at)) { + // At this point, we need to lookahead to determine if this @ is the start + // of an @catch or @finally. We don't want to consume the @ token if this + // is an @try or @encode or something else. + Token AfterAt = GetLookAheadToken(1); + if (!AfterAt.isObjCAtKeyword(tok::objc_catch) && + !AfterAt.isObjCAtKeyword(tok::objc_finally)) + break; + + SourceLocation AtCatchFinallyLoc = ConsumeToken(); + if (Tok.isObjCAtKeyword(tok::objc_catch)) { + StmtTy *FirstPart = 0; + ConsumeToken(); // consume catch + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + EnterScope(Scope::DeclScope); + if (Tok.isNot(tok::ellipsis)) { + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + // FIXME: Is BlockContext right? + Declarator DeclaratorInfo(DS, Declarator::BlockContext); + ParseDeclarator(DeclaratorInfo); + DeclTy *aBlockVarDecl = Actions.ActOnDeclarator(CurScope, + DeclaratorInfo, 0); + StmtResult stmtResult = + Actions.ActOnDeclStmt(aBlockVarDecl, DS.getSourceRange().getBegin(), + DeclaratorInfo.getSourceRange().getEnd()); + FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val; + } else + ConsumeToken(); // consume '...' + SourceLocation RParenLoc = ConsumeParen(); + + StmtResult CatchBody(true); + if (Tok.is(tok::l_brace)) + CatchBody = ParseCompoundStatementBody(); + else + Diag(Tok, diag::err_expected_lbrace); + if (CatchBody.isInvalid) + CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); + CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, RParenLoc, + FirstPart, CatchBody.Val, CatchStmts.Val); + ExitScope(); + } else { + Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after, + "@catch clause"); + return true; + } + catch_or_finally_seen = true; + } else { + assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?"); + ConsumeToken(); // consume finally + + StmtResult FinallyBody(true); + if (Tok.is(tok::l_brace)) + FinallyBody = ParseCompoundStatementBody(); + else + Diag(Tok, diag::err_expected_lbrace); + if (FinallyBody.isInvalid) + FinallyBody = Actions.ActOnNullStmt(Tok.getLocation()); + FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc, + FinallyBody.Val); + catch_or_finally_seen = true; + break; + } + } + if (!catch_or_finally_seen) { + Diag(atLoc, diag::err_missing_catch_finally); + return true; + } + return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.Val, CatchStmts.Val, + FinallyStmt.Val); +} + +/// objc-method-def: objc-method-proto ';'[opt] '{' body '}' +/// +Parser::DeclTy *Parser::ParseObjCMethodDefinition() { + DeclTy *MDecl = ParseObjCMethodPrototype(ObjCImpDecl); + // parse optional ';' + if (Tok.is(tok::semi)) + ConsumeToken(); + + // We should have an opening brace now. + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_method_body); + + // Skip over garbage, until we get to '{'. Don't eat the '{'. + SkipUntil(tok::l_brace, true, true); + + // If we didn't find the '{', bail out. + if (Tok.isNot(tok::l_brace)) + return 0; + } + SourceLocation BraceLoc = Tok.getLocation(); + + // Enter a scope for the method body. + EnterScope(Scope::FnScope|Scope::DeclScope); + + // Tell the actions module that we have entered a method definition with the + // specified Declarator for the method. + Actions.ObjCActOnStartOfMethodDef(CurScope, MDecl); + + StmtResult FnBody = ParseCompoundStatementBody(); + + // If the function body could not be parsed, make a bogus compoundstmt. + if (FnBody.isInvalid) + FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, 0, 0, false); + + // Leave the function body scope. + ExitScope(); + + // TODO: Pass argument information. + Actions.ActOnFinishFunctionBody(MDecl, FnBody.Val); + return MDecl; +} + +Parser::StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { + if (Tok.isObjCAtKeyword(tok::objc_try)) { + return ParseObjCTryStmt(AtLoc); + } else if (Tok.isObjCAtKeyword(tok::objc_throw)) + return ParseObjCThrowStmt(AtLoc); + else if (Tok.isObjCAtKeyword(tok::objc_synchronized)) + return ParseObjCSynchronizedStmt(AtLoc); + ExprResult Res = ParseExpressionWithLeadingAt(AtLoc); + if (Res.isInvalid) { + // If the expression is invalid, skip ahead to the next semicolon. Not + // doing this opens us up to the possibility of infinite loops if + // ParseExpression does not consume any tokens. + SkipUntil(tok::semi); + return true; + } + // Otherwise, eat the semicolon. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Res.Val); +} + +Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { + + switch (Tok.getKind()) { + case tok::string_literal: // primary-expression: string-literal + case tok::wide_string_literal: + return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); + default: + break; + } + + switch (Tok.getIdentifierInfo()->getObjCKeywordID()) { + case tok::objc_encode: + return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc)); + case tok::objc_protocol: + return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc)); + case tok::objc_selector: + return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc)); + default: + Diag(AtLoc, diag::err_unexpected_at); + SkipUntil(tok::semi); + return true; + } +} + +/// objc-message-expr: +/// '[' objc-receiver objc-message-args ']' +/// +/// objc-receiver: +/// expression +/// class-name +/// type-name +Parser::ExprResult Parser::ParseObjCMessageExpression() { + assert(Tok.is(tok::l_square) && "'[' expected"); + SourceLocation LBracLoc = ConsumeBracket(); // consume '[' + + // Parse receiver + if (isTokObjCMessageIdentifierReceiver()) { + IdentifierInfo *ReceiverName = Tok.getIdentifierInfo(); + ConsumeToken(); + return ParseObjCMessageExpressionBody(LBracLoc, ReceiverName, 0); + } + + ExprResult Res = ParseAssignmentExpression(); + if (Res.isInvalid) { + Diag(Tok, diag::err_invalid_receiver_to_message); + SkipUntil(tok::r_square); + return Res; + } + return ParseObjCMessageExpressionBody(LBracLoc, 0, Res.Val); +} + +/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse +/// the rest of a message expression. +/// +/// objc-message-args: +/// objc-selector +/// objc-keywordarg-list +/// +/// objc-keywordarg-list: +/// objc-keywordarg +/// objc-keywordarg-list objc-keywordarg +/// +/// objc-keywordarg: +/// selector-name[opt] ':' objc-keywordexpr +/// +/// objc-keywordexpr: +/// nonempty-expr-list +/// +/// nonempty-expr-list: +/// assignment-expression +/// nonempty-expr-list , assignment-expression +/// +Parser::ExprResult +Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, + IdentifierInfo *ReceiverName, + ExprTy *ReceiverExpr) { + // Parse objc-selector + SourceLocation Loc; + IdentifierInfo *selIdent = ParseObjCSelector(Loc); + + llvm::SmallVector KeyIdents; + llvm::SmallVector KeyExprs; + + if (Tok.is(tok::colon)) { + while (1) { + // Each iteration parses a single keyword argument. + KeyIdents.push_back(selIdent); + + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon); + SkipUntil(tok::semi); + return true; + } + ConsumeToken(); // Eat the ':'. + /// Parse the expression after ':' + ExprResult Res = ParseAssignmentExpression(); + if (Res.isInvalid) { + SkipUntil(tok::identifier); + return Res; + } + // We have a valid expression. + KeyExprs.push_back(Res.Val); + + // Check for another keyword selector. + selIdent = ParseObjCSelector(Loc); + if (!selIdent && Tok.isNot(tok::colon)) + break; + // We have a selector or a colon, continue parsing. + } + // Parse the, optional, argument list, comma separated. + while (Tok.is(tok::comma)) { + ConsumeToken(); // Eat the ','. + /// Parse the expression after ',' + ExprResult Res = ParseAssignmentExpression(); + if (Res.isInvalid) { + SkipUntil(tok::identifier); + return Res; + } + // We have a valid expression. + KeyExprs.push_back(Res.Val); + } + } else if (!selIdent) { + Diag(Tok, diag::err_expected_ident); // missing selector name. + SkipUntil(tok::semi); + return true; + } + + if (Tok.isNot(tok::r_square)) { + Diag(Tok, diag::err_expected_rsquare); + SkipUntil(tok::semi); + return true; + } + SourceLocation RBracLoc = ConsumeBracket(); // consume ']' + + unsigned nKeys = KeyIdents.size(); + if (nKeys == 0) + KeyIdents.push_back(selIdent); + Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); + + // We've just parsed a keyword message. + if (ReceiverName) + return Actions.ActOnClassMessage(CurScope, + ReceiverName, Sel, LBracLoc, RBracLoc, + &KeyExprs[0], KeyExprs.size()); + return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracLoc, RBracLoc, + &KeyExprs[0], KeyExprs.size()); +} + +Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { + ExprResult Res = ParseStringLiteralExpression(); + if (Res.isInvalid) return Res; + + // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string + // expressions. At this point, we know that the only valid thing that starts + // with '@' is an @"". + llvm::SmallVector AtLocs; + llvm::SmallVector AtStrings; + AtLocs.push_back(AtLoc); + AtStrings.push_back(Res.Val); + + while (Tok.is(tok::at)) { + AtLocs.push_back(ConsumeToken()); // eat the @. + + ExprResult Res(true); // Invalid unless there is a string literal. + if (isTokenStringLiteral()) + Res = ParseStringLiteralExpression(); + else + Diag(Tok, diag::err_objc_concat_string); + + if (Res.isInvalid) { + while (!AtStrings.empty()) { + Actions.DeleteExpr(AtStrings.back()); + AtStrings.pop_back(); + } + return Res; + } + + AtStrings.push_back(Res.Val); + } + + return Actions.ParseObjCStringLiteral(&AtLocs[0], &AtStrings[0], + AtStrings.size()); +} + +/// objc-encode-expression: +/// @encode ( type-name ) +Parser::ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { + assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!"); + + SourceLocation EncLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "@encode"); + return true; + } + + SourceLocation LParenLoc = ConsumeParen(); + + TypeTy *Ty = ParseTypeName(); + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, Ty, + RParenLoc); +} + +/// objc-protocol-expression +/// @protocol ( protocol-name ) + +Parser::ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) +{ + SourceLocation ProtoLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "@protocol"); + return true; + } + + SourceLocation LParenLoc = ConsumeParen(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + return true; + } + IdentifierInfo *protocolId = Tok.getIdentifierInfo(); + ConsumeToken(); + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, + LParenLoc, RParenLoc); +} + +/// objc-selector-expression +/// @selector '(' objc-keyword-selector ')' +Parser::ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) +{ + SourceLocation SelectorLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "@selector"); + return 0; + } + + llvm::SmallVector KeyIdents; + SourceLocation LParenLoc = ConsumeParen(); + SourceLocation sLoc; + IdentifierInfo *SelIdent = ParseObjCSelector(sLoc); + if (!SelIdent && Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_ident); // missing selector name. + return 0; + } + KeyIdents.push_back(SelIdent); + unsigned nColons = 0; + if (Tok.isNot(tok::r_paren)) { + while (1) { + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon); + break; + } + nColons++; + ConsumeToken(); // Eat the ':'. + if (Tok.is(tok::r_paren)) + break; + // Check for another keyword selector. + SourceLocation Loc; + SelIdent = ParseObjCSelector(Loc); + KeyIdents.push_back(SelIdent); + if (!SelIdent && Tok.isNot(tok::colon)) + break; + } + } + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]); + return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc, LParenLoc, + RParenLoc); + } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp new file mode 100644 index 00000000000..f9800219ed5 --- /dev/null +++ b/clang/lib/Parse/ParseStmt.cpp @@ -0,0 +1,1159 @@ +//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Statement and Block portions of the Parser +// interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// C99 6.8: Statements and Blocks. +//===----------------------------------------------------------------------===// + +/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'. +/// StatementOrDeclaration: +/// statement +/// declaration +/// +/// statement: +/// labeled-statement +/// compound-statement +/// expression-statement +/// selection-statement +/// iteration-statement +/// jump-statement +/// [OBC] objc-throw-statement +/// [OBC] objc-try-catch-statement +/// [OBC] objc-synchronized-statement +/// [GNU] asm-statement +/// [OMP] openmp-construct [TODO] +/// +/// labeled-statement: +/// identifier ':' statement +/// 'case' constant-expression ':' statement +/// 'default' ':' statement +/// +/// selection-statement: +/// if-statement +/// switch-statement +/// +/// iteration-statement: +/// while-statement +/// do-statement +/// for-statement +/// +/// expression-statement: +/// expression[opt] ';' +/// +/// jump-statement: +/// 'goto' identifier ';' +/// 'continue' ';' +/// 'break' ';' +/// 'return' expression[opt] ';' +/// [GNU] 'goto' '*' expression ';' +/// +/// [OBC] objc-throw-statement: +/// [OBC] '@' 'throw' expression ';' +/// [OBC] '@' 'throw' ';' +/// +Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { + const char *SemiError = 0; + Parser::StmtResult Res; + + // Cases in this switch statement should fall through if the parser expects + // the token to end in a semicolon (in which case SemiError should be set), + // or they directly 'return;' if not. + tok::TokenKind Kind = Tok.getKind(); + SourceLocation AtLoc; + switch (Kind) { + case tok::identifier: // C99 6.8.1: labeled-statement + // identifier ':' statement + // declaration (if !OnlyStatement) + // expression[opt] ';' + return ParseIdentifierStatement(OnlyStatement); + + case tok::at: // May be a @try or @throw statement + { + AtLoc = ConsumeToken(); // consume @ + return ParseObjCAtStatement(AtLoc); + } + + default: + if (!OnlyStatement && isDeclarationSpecifier()) { + SourceLocation DeclStart = Tok.getLocation(); + DeclTy *Res = ParseDeclaration(Declarator::BlockContext); + // FIXME: Pass in the right location for the end of the declstmt. + return Actions.ActOnDeclStmt(Res, DeclStart, DeclStart); + } else if (Tok.is(tok::r_brace)) { + Diag(Tok, diag::err_expected_statement); + return true; + } else { + // expression[opt] ';' + ExprResult Res = ParseExpression(); + if (Res.isInvalid) { + // If the expression is invalid, skip ahead to the next semicolon. Not + // doing this opens us up to the possibility of infinite loops if + // ParseExpression does not consume any tokens. + SkipUntil(tok::semi); + return true; + } + // Otherwise, eat the semicolon. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Res.Val); + } + + case tok::kw_case: // C99 6.8.1: labeled-statement + return ParseCaseStatement(); + case tok::kw_default: // C99 6.8.1: labeled-statement + return ParseDefaultStatement(); + + case tok::l_brace: // C99 6.8.2: compound-statement + return ParseCompoundStatement(); + case tok::semi: // C99 6.8.3p3: expression[opt] ';' + return Actions.ActOnNullStmt(ConsumeToken()); + + case tok::kw_if: // C99 6.8.4.1: if-statement + return ParseIfStatement(); + case tok::kw_switch: // C99 6.8.4.2: switch-statement + return ParseSwitchStatement(); + + case tok::kw_while: // C99 6.8.5.1: while-statement + return ParseWhileStatement(); + case tok::kw_do: // C99 6.8.5.2: do-statement + Res = ParseDoStatement(); + SemiError = "do/while loop"; + break; + case tok::kw_for: // C99 6.8.5.3: for-statement + return ParseForStatement(); + + case tok::kw_goto: // C99 6.8.6.1: goto-statement + Res = ParseGotoStatement(); + SemiError = "goto statement"; + break; + case tok::kw_continue: // C99 6.8.6.2: continue-statement + Res = ParseContinueStatement(); + SemiError = "continue statement"; + break; + case tok::kw_break: // C99 6.8.6.3: break-statement + Res = ParseBreakStatement(); + SemiError = "break statement"; + break; + case tok::kw_return: // C99 6.8.6.4: return-statement + Res = ParseReturnStatement(); + SemiError = "return statement"; + break; + + case tok::kw_asm: + bool msAsm = false; + Res = ParseAsmStatement(msAsm); + if (msAsm) return Res; + SemiError = "asm statement"; + break; + } + + // If we reached this code, the statement must end in a semicolon. + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_semi_after, SemiError); + SkipUntil(tok::semi); + } + return Res; +} + +/// ParseIdentifierStatement - Because we don't have two-token lookahead, we +/// have a bit of a quandry here. Reading the identifier is necessary to see if +/// there is a ':' after it. If there is, this is a label, regardless of what +/// else the identifier can mean. If not, this is either part of a declaration +/// (if the identifier is a type-name) or part of an expression. +/// +/// labeled-statement: +/// identifier ':' statement +/// [GNU] identifier ':' attributes[opt] statement +/// declaration (if !OnlyStatement) +/// expression[opt] ';' +/// +Parser::StmtResult Parser::ParseIdentifierStatement(bool OnlyStatement) { + assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && + "Not an identifier!"); + + Token IdentTok = Tok; // Save the whole token. + ConsumeToken(); // eat the identifier. + + // identifier ':' statement + if (Tok.is(tok::colon)) { + SourceLocation ColonLoc = ConsumeToken(); + + // Read label attributes, if present. + DeclTy *AttrList = 0; + if (Tok.is(tok::kw___attribute)) + // TODO: save these somewhere. + AttrList = ParseAttributes(); + + StmtResult SubStmt = ParseStatement(); + + // Broken substmt shouldn't prevent the label from being added to the AST. + if (SubStmt.isInvalid) + SubStmt = Actions.ActOnNullStmt(ColonLoc); + + return Actions.ActOnLabelStmt(IdentTok.getLocation(), + IdentTok.getIdentifierInfo(), + ColonLoc, SubStmt.Val); + } + + // Check to see if this is a declaration. + void *TypeRep; + if (!OnlyStatement && + (TypeRep = Actions.isTypeName(*IdentTok.getIdentifierInfo(), CurScope))) { + // Handle this. Warn/disable if in middle of block and !C99. + DeclSpec DS; + + // Add the typedef name to the start of the decl-specs. + const char *PrevSpec = 0; + int isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, + IdentTok.getLocation(), PrevSpec, + TypeRep); + assert(!isInvalid && "First declspec can't be invalid!"); + SourceLocation endProtoLoc; + if (Tok.is(tok::less)) { + llvm::SmallVector ProtocolRefs; + ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc); + llvm::SmallVector *ProtocolDecl = + new llvm::SmallVector; + DS.setProtocolQualifiers(ProtocolDecl); + Actions.FindProtocolDeclaration(IdentTok.getLocation(), + &ProtocolRefs[0], ProtocolRefs.size(), + *ProtocolDecl); + } + + // ParseDeclarationSpecifiers will continue from there. + ParseDeclarationSpecifiers(DS); + + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" + // declaration-specifiers init-declarator-list[opt] ';' + if (Tok.is(tok::semi)) { + // TODO: emit error on 'int;' or 'const enum foo;'. + // if (!DS.isMissingDeclaratorOk()) Diag(...); + + ConsumeToken(); + // FIXME: Return this as a type decl. + return 0; + } + + // Parse all the declarators. + Declarator DeclaratorInfo(DS, Declarator::BlockContext); + ParseDeclarator(DeclaratorInfo); + + DeclTy *Decl = ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); + if (!Decl) return 0; + return Actions.ActOnDeclStmt(Decl, DS.getSourceRange().getBegin(), + DeclaratorInfo.getSourceRange().getEnd()); + } + + // Otherwise, this is an expression. Seed it with II and parse it. + ExprResult Res = ParseExpressionWithLeadingIdentifier(IdentTok); + if (Res.isInvalid) { + SkipUntil(tok::semi); + return true; + } else if (Tok.isNot(tok::semi)) { + Diag(Tok, diag::err_expected_semi_after, "expression"); + SkipUntil(tok::semi); + return true; + } else { + ConsumeToken(); + // Convert expr to a stmt. + return Actions.ActOnExprStmt(Res.Val); + } +} + +/// ParseCaseStatement +/// labeled-statement: +/// 'case' constant-expression ':' statement +/// [GNU] 'case' constant-expression '...' constant-expression ':' statement +/// +/// Note that this does not parse the 'statement' at the end. +/// +Parser::StmtResult Parser::ParseCaseStatement() { + assert(Tok.is(tok::kw_case) && "Not a case stmt!"); + SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'. + + ExprResult LHS = ParseConstantExpression(); + if (LHS.isInvalid) { + SkipUntil(tok::colon); + return true; + } + + // GNU case range extension. + SourceLocation DotDotDotLoc; + ExprTy *RHSVal = 0; + if (Tok.is(tok::ellipsis)) { + Diag(Tok, diag::ext_gnu_case_range); + DotDotDotLoc = ConsumeToken(); + + ExprResult RHS = ParseConstantExpression(); + if (RHS.isInvalid) { + SkipUntil(tok::colon); + return true; + } + RHSVal = RHS.Val; + } + + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon_after, "'case'"); + SkipUntil(tok::colon); + return true; + } + + SourceLocation ColonLoc = ConsumeToken(); + + // Diagnose the common error "switch (X) { case 4: }", which is not valid. + if (Tok.is(tok::r_brace)) { + Diag(Tok, diag::err_label_end_of_compound_statement); + return true; + } + + StmtResult SubStmt = ParseStatement(); + + // Broken substmt shouldn't prevent the case from being added to the AST. + if (SubStmt.isInvalid) + SubStmt = Actions.ActOnNullStmt(ColonLoc); + + return Actions.ActOnCaseStmt(CaseLoc, LHS.Val, DotDotDotLoc, RHSVal, ColonLoc, + SubStmt.Val); +} + +/// ParseDefaultStatement +/// labeled-statement: +/// 'default' ':' statement +/// Note that this does not parse the 'statement' at the end. +/// +Parser::StmtResult Parser::ParseDefaultStatement() { + assert(Tok.is(tok::kw_default) && "Not a default stmt!"); + SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. + + if (Tok.isNot(tok::colon)) { + Diag(Tok, diag::err_expected_colon_after, "'default'"); + SkipUntil(tok::colon); + return true; + } + + SourceLocation ColonLoc = ConsumeToken(); + + // Diagnose the common error "switch (X) {... default: }", which is not valid. + if (Tok.is(tok::r_brace)) { + Diag(Tok, diag::err_label_end_of_compound_statement); + return true; + } + + StmtResult SubStmt = ParseStatement(); + if (SubStmt.isInvalid) + return true; + + return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt.Val, CurScope); +} + + +/// ParseCompoundStatement - Parse a "{}" block. +/// +/// compound-statement: [C99 6.8.2] +/// { block-item-list[opt] } +/// [GNU] { label-declarations block-item-list } [TODO] +/// +/// block-item-list: +/// block-item +/// block-item-list block-item +/// +/// block-item: +/// declaration +/// [GNU] '__extension__' declaration +/// statement +/// [OMP] openmp-directive [TODO] +/// +/// [GNU] label-declarations: +/// [GNU] label-declaration +/// [GNU] label-declarations label-declaration +/// +/// [GNU] label-declaration: +/// [GNU] '__label__' identifier-list ';' +/// +/// [OMP] openmp-directive: [TODO] +/// [OMP] barrier-directive +/// [OMP] flush-directive +/// +Parser::StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { + assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); + + // Enter a scope to hold everything within the compound stmt. Compound + // statements can always hold declarations. + EnterScope(Scope::DeclScope); + + // Parse the statements in the body. + StmtResult Body = ParseCompoundStatementBody(isStmtExpr); + + ExitScope(); + return Body; +} + + +/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the +/// ActOnCompoundStmt action. This expects the '{' to be the current token, and +/// consume the '}' at the end of the block. It does not manipulate the scope +/// stack. +Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { + SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'. + + // TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are + // only allowed at the start of a compound stmt regardless of the language. + + llvm::SmallVector Stmts; + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + StmtResult R; + if (Tok.isNot(tok::kw___extension__)) { + R = ParseStatementOrDeclaration(false); + } else { + // __extension__ can start declarations and it can also be a unary + // operator for expressions. Consume multiple __extension__ markers here + // until we can determine which is which. + SourceLocation ExtLoc = ConsumeToken(); + while (Tok.is(tok::kw___extension__)) + ConsumeToken(); + + // __extension__ silences extension warnings in the subexpression. + bool SavedExtWarn = Diags.getWarnOnExtensions(); + Diags.setWarnOnExtensions(false); + + // If this is the start of a declaration, parse it as such. + if (isDeclarationSpecifier()) { + // FIXME: Save the __extension__ on the decl as a node somehow. + SourceLocation DeclStart = Tok.getLocation(); + DeclTy *Res = ParseDeclaration(Declarator::BlockContext); + // FIXME: Pass in the right location for the end of the declstmt. + R = Actions.ActOnDeclStmt(Res, DeclStart, DeclStart); + + Diags.setWarnOnExtensions(SavedExtWarn); + } else { + // Otherwise this was a unary __extension__ marker. Parse the + // subexpression and add the __extension__ unary op. + ExprResult Res = ParseCastExpression(false); + Diags.setWarnOnExtensions(SavedExtWarn); + + if (Res.isInvalid) { + SkipUntil(tok::semi); + continue; + } + + // Add the __extension__ node to the AST. + Res = Actions.ActOnUnaryOp(ExtLoc, tok::kw___extension__, Res.Val); + if (Res.isInvalid) + continue; + + // Eat the semicolon at the end of stmt and convert the expr into a stmt. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); + R = Actions.ActOnExprStmt(Res.Val); + } + } + + if (!R.isInvalid && R.Val) + Stmts.push_back(R.Val); + } + + // We broke out of the while loop because we found a '}' or EOF. + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + return true; + } + + SourceLocation RBraceLoc = ConsumeBrace(); + return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc, + &Stmts[0], Stmts.size(), isStmtExpr); +} + +/// ParseIfStatement +/// if-statement: [C99 6.8.4.1] +/// 'if' '(' expression ')' statement +/// 'if' '(' expression ')' statement 'else' statement +/// +Parser::StmtResult Parser::ParseIfStatement() { + assert(Tok.is(tok::kw_if) && "Not an if stmt!"); + SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "if"); + SkipUntil(tok::semi); + return true; + } + + // C99 6.8.4p3 - In C99, the if statement is a block. This is not + // the case for C90. + if (getLang().C99) + EnterScope(Scope::DeclScope); + + // Parse the condition. + ExprResult CondExp = ParseSimpleParenExpression(); + if (CondExp.isInvalid) { + SkipUntil(tok::semi); + if (getLang().C99) + ExitScope(); + return true; + } + + // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); + if (NeedsInnerScope) EnterScope(Scope::DeclScope); + + // Read the 'then' stmt. + SourceLocation ThenStmtLoc = Tok.getLocation(); + StmtResult ThenStmt = ParseStatement(); + + // Pop the 'if' scope if needed. + if (NeedsInnerScope) ExitScope(); + + // If it has an else, parse it. + SourceLocation ElseLoc; + SourceLocation ElseStmtLoc; + StmtResult ElseStmt(false); + + if (Tok.is(tok::kw_else)) { + ElseLoc = ConsumeToken(); + + // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do + // this if the body isn't a compound statement to avoid push/pop in common + // cases. + NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); + if (NeedsInnerScope) EnterScope(Scope::DeclScope); + + ElseStmtLoc = Tok.getLocation(); + ElseStmt = ParseStatement(); + + // Pop the 'else' scope if needed. + if (NeedsInnerScope) ExitScope(); + } + + if (getLang().C99) + ExitScope(); + + // If the then or else stmt is invalid and the other is valid (and present), + // make turn the invalid one into a null stmt to avoid dropping the other + // part. If both are invalid, return error. + if ((ThenStmt.isInvalid && ElseStmt.isInvalid) || + (ThenStmt.isInvalid && ElseStmt.Val == 0) || + (ThenStmt.Val == 0 && ElseStmt.isInvalid)) { + // Both invalid, or one is invalid and other is non-present: delete cond and + // return error. + Actions.DeleteExpr(CondExp.Val); + return true; + } + + // Now if either are invalid, replace with a ';'. + if (ThenStmt.isInvalid) + ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); + if (ElseStmt.isInvalid) + ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); + + return Actions.ActOnIfStmt(IfLoc, CondExp.Val, ThenStmt.Val, + ElseLoc, ElseStmt.Val); +} + +/// ParseSwitchStatement +/// switch-statement: +/// 'switch' '(' expression ')' statement +Parser::StmtResult Parser::ParseSwitchStatement() { + assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); + SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "switch"); + SkipUntil(tok::semi); + return true; + } + + // C99 6.8.4p3 - In C99, the switch statement is a block. This is + // not the case for C90. Start the switch scope. + if (getLang().C99) + EnterScope(Scope::BreakScope|Scope::DeclScope); + else + EnterScope(Scope::BreakScope); + + // Parse the condition. + ExprResult Cond = ParseSimpleParenExpression(); + + if (Cond.isInvalid) { + ExitScope(); + return true; + } + + StmtResult Switch = Actions.ActOnStartOfSwitchStmt(Cond.Val); + + // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); + if (NeedsInnerScope) EnterScope(Scope::DeclScope); + + // Read the body statement. + StmtResult Body = ParseStatement(); + + // Pop the body scope if needed. + if (NeedsInnerScope) ExitScope(); + + if (Body.isInvalid) { + Body = Actions.ActOnNullStmt(Tok.getLocation()); + // FIXME: Remove the case statement list from the Switch statement. + } + + ExitScope(); + + return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.Val, Body.Val); +} + +/// ParseWhileStatement +/// while-statement: [C99 6.8.5.1] +/// 'while' '(' expression ')' statement +Parser::StmtResult Parser::ParseWhileStatement() { + assert(Tok.is(tok::kw_while) && "Not a while stmt!"); + SourceLocation WhileLoc = Tok.getLocation(); + ConsumeToken(); // eat the 'while'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "while"); + SkipUntil(tok::semi); + return true; + } + + // C99 6.8.5p5 - In C99, the while statement is a block. This is not + // the case for C90. Start the loop scope. + if (getLang().C99) + EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); + else + EnterScope(Scope::BreakScope | Scope::ContinueScope); + + // Parse the condition. + ExprResult Cond = ParseSimpleParenExpression(); + + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); + if (NeedsInnerScope) EnterScope(Scope::DeclScope); + + // Read the body statement. + StmtResult Body = ParseStatement(); + + // Pop the body scope if needed. + if (NeedsInnerScope) ExitScope(); + + ExitScope(); + + if (Cond.isInvalid || Body.isInvalid) return true; + + return Actions.ActOnWhileStmt(WhileLoc, Cond.Val, Body.Val); +} + +/// ParseDoStatement +/// do-statement: [C99 6.8.5.2] +/// 'do' statement 'while' '(' expression ')' ';' +/// Note: this lets the caller parse the end ';'. +Parser::StmtResult Parser::ParseDoStatement() { + assert(Tok.is(tok::kw_do) && "Not a do stmt!"); + SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. + + // C99 6.8.5p5 - In C99, the do statement is a block. This is not + // the case for C90. Start the loop scope. + if (getLang().C99) + EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); + else + EnterScope(Scope::BreakScope | Scope::ContinueScope); + + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); + if (NeedsInnerScope) EnterScope(Scope::DeclScope); + + // Read the body statement. + StmtResult Body = ParseStatement(); + + // Pop the body scope if needed. + if (NeedsInnerScope) ExitScope(); + + if (Tok.isNot(tok::kw_while)) { + ExitScope(); + Diag(Tok, diag::err_expected_while); + Diag(DoLoc, diag::err_matching, "do"); + SkipUntil(tok::semi); + return true; + } + SourceLocation WhileLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + ExitScope(); + Diag(Tok, diag::err_expected_lparen_after, "do/while"); + SkipUntil(tok::semi); + return true; + } + + // Parse the condition. + ExprResult Cond = ParseSimpleParenExpression(); + + ExitScope(); + + if (Cond.isInvalid || Body.isInvalid) return true; + + return Actions.ActOnDoStmt(DoLoc, Body.Val, WhileLoc, Cond.Val); +} + +/// ParseForStatement +/// for-statement: [C99 6.8.5.3] +/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement +/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement +/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement +/// [OBJC2] 'for' '(' expr 'in' expr ')' statement +Parser::StmtResult Parser::ParseForStatement() { + assert(Tok.is(tok::kw_for) && "Not a for stmt!"); + SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "for"); + SkipUntil(tok::semi); + return true; + } + + // C99 6.8.5p5 - In C99, the for statement is a block. This is not + // the case for C90. Start the loop scope. + if (getLang().C99) + EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope); + else + EnterScope(Scope::BreakScope | Scope::ContinueScope); + + SourceLocation LParenLoc = ConsumeParen(); + ExprResult Value; + + StmtTy *FirstPart = 0; + ExprTy *SecondPart = 0; + StmtTy *ThirdPart = 0; + bool ForEach = false; + + // Parse the first part of the for specifier. + if (Tok.is(tok::semi)) { // for (; + // no first part, eat the ';'. + ConsumeToken(); + } else if (isDeclarationSpecifier()) { // for (int X = 4; + // Parse declaration, which eats the ';'. + if (!getLang().C99) // Use of C99-style for loops in C90 mode? + Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); + + SourceLocation DeclStart = Tok.getLocation(); + DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext); + // FIXME: Pass in the right location for the end of the declstmt. + StmtResult stmtResult = Actions.ActOnDeclStmt(aBlockVarDecl, DeclStart, + DeclStart); + FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val; + if ((ForEach = isTokIdentifier_in())) { + ConsumeToken(); // consume 'in' + Value = ParseExpression(); + if (!Value.isInvalid) + SecondPart = Value.Val; + } + } else { + Value = ParseExpression(); + + // Turn the expression into a stmt. + if (!Value.isInvalid) { + StmtResult R = Actions.ActOnExprStmt(Value.Val); + if (!R.isInvalid) + FirstPart = R.Val; + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } + else if ((ForEach = isTokIdentifier_in())) { + ConsumeToken(); // consume 'in' + Value = ParseExpression(); + if (!Value.isInvalid) + SecondPart = Value.Val; + } + else { + if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for); + SkipUntil(tok::semi); + } + } + if (!ForEach) { + // Parse the second part of the for specifier. + if (Tok.is(tok::semi)) { // for (...;; + // no second part. + Value = ExprResult(); + } else { + Value = ParseExpression(); + if (!Value.isInvalid) + SecondPart = Value.Val; + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else { + if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for); + SkipUntil(tok::semi); + } + + // Parse the third part of the for specifier. + if (Tok.is(tok::r_paren)) { // for (...;...;) + // no third part. + Value = ExprResult(); + } else { + Value = ParseExpression(); + if (!Value.isInvalid) { + // Turn the expression into a stmt. + StmtResult R = Actions.ActOnExprStmt(Value.Val); + if (!R.isInvalid) + ThirdPart = R.Val; + } + } + } + // Match the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if + // there is no compound stmt. C90 does not have this clause. We only do this + // if the body isn't a compound statement to avoid push/pop in common cases. + bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace); + if (NeedsInnerScope) EnterScope(Scope::DeclScope); + + // Read the body statement. + StmtResult Body = ParseStatement(); + + // Pop the body scope if needed. + if (NeedsInnerScope) ExitScope(); + + // Leave the for-scope. + ExitScope(); + + if (Body.isInvalid) + return Body; + + if (!ForEach) + return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart, + SecondPart, ThirdPart, RParenLoc, Body.Val); + else + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart, + SecondPart, RParenLoc, Body.Val); +} + +/// ParseGotoStatement +/// jump-statement: +/// 'goto' identifier ';' +/// [GNU] 'goto' '*' expression ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +Parser::StmtResult Parser::ParseGotoStatement() { + assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); + SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. + + StmtResult Res; + if (Tok.is(tok::identifier)) { + Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), + Tok.getIdentifierInfo()); + ConsumeToken(); + } else if (Tok.is(tok::star) && !getLang().NoExtensions) { + // GNU indirect goto extension. + Diag(Tok, diag::ext_gnu_indirect_goto); + SourceLocation StarLoc = ConsumeToken(); + ExprResult R = ParseExpression(); + if (R.isInvalid) { // Skip to the semicolon, but don't consume it. + SkipUntil(tok::semi, false, true); + return true; + } + Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.Val); + } else { + Diag(Tok, diag::err_expected_ident); + return true; + } + + return Res; +} + +/// ParseContinueStatement +/// jump-statement: +/// 'continue' ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +Parser::StmtResult Parser::ParseContinueStatement() { + SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. + return Actions.ActOnContinueStmt(ContinueLoc, CurScope); +} + +/// ParseBreakStatement +/// jump-statement: +/// 'break' ';' +/// +/// Note: this lets the caller parse the end ';'. +/// +Parser::StmtResult Parser::ParseBreakStatement() { + SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. + return Actions.ActOnBreakStmt(BreakLoc, CurScope); +} + +/// ParseReturnStatement +/// jump-statement: +/// 'return' expression[opt] ';' +Parser::StmtResult Parser::ParseReturnStatement() { + assert(Tok.is(tok::kw_return) && "Not a return stmt!"); + SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. + + ExprResult R(0); + if (Tok.isNot(tok::semi)) { + R = ParseExpression(); + if (R.isInvalid) { // Skip to the semicolon, but don't consume it. + SkipUntil(tok::semi, false, true); + return true; + } + } + return Actions.ActOnReturnStmt(ReturnLoc, R.Val); +} + +/// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this +/// routine is called to skip/ignore tokens that comprise the MS asm statement. +Parser::StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { + if (Tok.is(tok::l_brace)) { + unsigned short savedBraceCount = BraceCount; + do { + ConsumeAnyToken(); + } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); + } else { + // From the MS website: If used without braces, the __asm keyword means + // that the rest of the line is an assembly-language statement. + SourceManager &SrcMgr = PP.getSourceManager(); + SourceLocation TokLoc = Tok.getLocation(); + unsigned lineNo = SrcMgr.getLogicalLineNumber(TokLoc); + do { + ConsumeAnyToken(); + TokLoc = Tok.getLocation(); + } while ((SrcMgr.getLogicalLineNumber(TokLoc) == lineNo) && + Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && + Tok.isNot(tok::eof)); + } + return false; +} + +/// ParseAsmStatement - Parse a GNU extended asm statement. +/// asm-statement: +/// gnu-asm-statement +/// ms-asm-statement +/// +/// [GNU] gnu-asm-statement: +/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' +/// +/// [GNU] asm-argument: +/// asm-string-literal +/// asm-string-literal ':' asm-operands[opt] +/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] +/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] +/// ':' asm-clobbers +/// +/// [GNU] asm-clobbers: +/// asm-string-literal +/// asm-clobbers ',' asm-string-literal +/// +/// [MS] ms-asm-statement: +/// '__asm' assembly-instruction ';'[opt] +/// '__asm' '{' assembly-instruction-list '}' ';'[opt] +/// +/// [MS] assembly-instruction-list: +/// assembly-instruction ';'[opt] +/// assembly-instruction-list ';' assembly-instruction ';'[opt] +/// +Parser::StmtResult Parser::ParseAsmStatement(bool &msAsm) { + assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); + SourceLocation AsmLoc = ConsumeToken(); + + if (getLang().Microsoft && Tok.isNot(tok::l_paren) && !isTypeQualifier()) { + msAsm = true; + return FuzzyParseMicrosoftAsmStatement(); + } + DeclSpec DS; + SourceLocation Loc = Tok.getLocation(); + ParseTypeQualifierListOpt(DS); + + // GNU asms accept, but warn, about type-qualifiers other than volatile. + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(Loc, diag::w_asm_qualifier_ignored, "const"); + if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) + Diag(Loc, diag::w_asm_qualifier_ignored, "restrict"); + + // Remember if this was a volatile asm. + bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; + bool isSimple = false; + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "asm"); + SkipUntil(tok::r_paren); + return true; + } + Loc = ConsumeParen(); + + ExprResult AsmString = ParseAsmStringLiteral(); + if (AsmString.isInvalid) + return true; + + llvm::SmallVector Names; + llvm::SmallVector Constraints; + llvm::SmallVector Exprs; + llvm::SmallVector Clobbers; + + unsigned NumInputs = 0, NumOutputs = 0; + + SourceLocation RParenLoc; + if (Tok.is(tok::r_paren)) { + // We have a simple asm expression + isSimple = true; + + RParenLoc = ConsumeParen(); + } else { + // Parse Outputs, if present. + if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return true; + + NumOutputs = Names.size(); + + // Parse Inputs, if present. + if (ParseAsmOperandsOpt(Names, Constraints, Exprs)) + return true; + + assert(Names.size() == Constraints.size() && + Constraints.size() == Exprs.size() + && "Input operand size mismatch!"); + + NumInputs = Names.size() - NumOutputs; + + // Parse the clobbers, if present. + if (Tok.is(tok::colon)) { + ConsumeToken(); + + // Parse the asm-string list for clobbers. + while (1) { + ExprResult Clobber = ParseAsmStringLiteral(); + + if (Clobber.isInvalid) + break; + + Clobbers.push_back(Clobber.Val); + + if (Tok.isNot(tok::comma)) break; + ConsumeToken(); + } + } + + RParenLoc = MatchRHSPunctuation(tok::r_paren, Loc); + } + + return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile, + NumOutputs, NumInputs, + &Names[0], &Constraints[0], &Exprs[0], + AsmString.Val, + Clobbers.size(), &Clobbers[0], + RParenLoc); +} + +/// ParseAsmOperands - Parse the asm-operands production as used by +/// asm-statement. We also parse a leading ':' token. If the leading colon is +/// not present, we do not parse anything. +/// +/// [GNU] asm-operands: +/// asm-operand +/// asm-operands ',' asm-operand +/// +/// [GNU] asm-operand: +/// asm-string-literal '(' expression ')' +/// '[' identifier ']' asm-string-literal '(' expression ')' +/// +bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, + llvm::SmallVectorImpl &Constraints, + llvm::SmallVectorImpl &Exprs) { + // Only do anything if this operand is present. + if (Tok.isNot(tok::colon)) return false; + ConsumeToken(); + + // 'asm-operands' isn't present? + if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) + return false; + + while (1) { + // Read the [id] if present. + if (Tok.is(tok::l_square)) { + SourceLocation Loc = ConsumeBracket(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::r_paren); + return true; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + ConsumeToken(); + + Names.push_back(std::string(II->getName(), II->getLength())); + MatchRHSPunctuation(tok::r_square, Loc); + } else + Names.push_back(std::string()); + + ExprResult Constraint = ParseAsmStringLiteral(); + if (Constraint.isInvalid) { + SkipUntil(tok::r_paren); + return true; + } + Constraints.push_back(Constraint.Val); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "asm operand"); + SkipUntil(tok::r_paren); + return true; + } + + // Read the parenthesized expression. + ExprResult Res = ParseSimpleParenExpression(); + if (Res.isInvalid) { + SkipUntil(tok::r_paren); + return true; + } + Exprs.push_back(Res.Val); + // Eat the comma and continue parsing if it exists. + if (Tok.isNot(tok::comma)) return false; + ConsumeToken(); + } + + return true; +} + +Parser::DeclTy *Parser::ParseFunctionStatementBody(DeclTy *Decl, + SourceLocation L, SourceLocation R) { + // Do not enter a scope for the brace, as the arguments are in the same scope + // (the function body) as the body itself. Instead, just read the statement + // list and put it into a CompoundStmt for safe keeping. + StmtResult FnBody = ParseCompoundStatementBody(); + + // If the function body could not be parsed, make a bogus compoundstmt. + if (FnBody.isInvalid) + FnBody = Actions.ActOnCompoundStmt(L, R, 0, 0, false); + + // Leave the function body scope. + ExitScope(); + + return Actions.ActOnFinishFunctionBody(Decl, FnBody.Val); +} diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp new file mode 100644 index 00000000000..703144b3c44 --- /dev/null +++ b/clang/lib/Parse/Parser.cpp @@ -0,0 +1,647 @@ +//===--- Parser.cpp - C Language Family Parser ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Parser interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +using namespace clang; + +Parser::Parser(Preprocessor &pp, Action &actions) + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) { + Tok.setKind(tok::eof); + CurScope = 0; + NumCachedScopes = 0; + ParenCount = BracketCount = BraceCount = 0; + ObjCImpDecl = 0; +} + +/// Out-of-line virtual destructor to provide home for Action class. +Action::~Action() {} + + +void Parser::Diag(SourceLocation Loc, unsigned DiagID, + const std::string &Msg) { + Diags.Report(FullSourceLoc(Loc,PP.getSourceManager()), DiagID, &Msg, 1); +} + +/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'), +/// this helper function matches and consumes the specified RHS token if +/// present. If not present, it emits the specified diagnostic indicating +/// that the parser failed to match the RHS of the token at LHSLoc. LHSName +/// should be the name of the unmatched LHS token. +SourceLocation Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, + SourceLocation LHSLoc) { + + if (Tok.is(RHSTok)) + return ConsumeAnyToken(); + + SourceLocation R = Tok.getLocation(); + const char *LHSName = "unknown"; + diag::kind DID = diag::err_parse_error; + switch (RHSTok) { + default: break; + case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break; + case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break; + case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break; + case tok::greater: LHSName = "<"; DID = diag::err_expected_greater; break; + } + Diag(Tok, DID); + Diag(LHSLoc, diag::err_matching, LHSName); + SkipUntil(RHSTok); + return R; +} + +/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the +/// input. If so, it is consumed and false is returned. +/// +/// If the input is malformed, this emits the specified diagnostic. Next, if +/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is +/// returned. +bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID, + const char *Msg, tok::TokenKind SkipToTok) { + if (Tok.is(ExpectedTok)) { + ConsumeAnyToken(); + return false; + } + + Diag(Tok, DiagID, Msg); + if (SkipToTok != tok::unknown) + SkipUntil(SkipToTok); + return true; +} + +//===----------------------------------------------------------------------===// +// Error recovery. +//===----------------------------------------------------------------------===// + +/// SkipUntil - Read tokens until we get to the specified token, then consume +/// it (unless DontConsume is true). Because we cannot guarantee that the +/// token will ever occur, this skips to the next token, or to some likely +/// good stopping point. If StopAtSemi is true, skipping will stop at a ';' +/// character. +/// +/// If SkipUntil finds the specified token, it returns true, otherwise it +/// returns false. +bool Parser::SkipUntil(const tok::TokenKind *Toks, unsigned NumToks, + bool StopAtSemi, bool DontConsume) { + // We always want this function to skip at least one token if the first token + // isn't T and if not at EOF. + bool isFirstTokenSkipped = true; + while (1) { + // If we found one of the tokens, stop and return true. + for (unsigned i = 0; i != NumToks; ++i) { + if (Tok.is(Toks[i])) { + if (DontConsume) { + // Noop, don't consume the token. + } else { + ConsumeAnyToken(); + } + return true; + } + } + + switch (Tok.getKind()) { + case tok::eof: + // Ran out of tokens. + return false; + + case tok::l_paren: + // Recursively skip properly-nested parens. + ConsumeParen(); + SkipUntil(tok::r_paren, false); + break; + case tok::l_square: + // Recursively skip properly-nested square brackets. + ConsumeBracket(); + SkipUntil(tok::r_square, false); + break; + case tok::l_brace: + // Recursively skip properly-nested braces. + ConsumeBrace(); + SkipUntil(tok::r_brace, false); + break; + + // Okay, we found a ']' or '}' or ')', which we think should be balanced. + // Since the user wasn't looking for this token (if they were, it would + // already be handled), this isn't balanced. If there is a LHS token at a + // higher level, we will assume that this matches the unbalanced token + // and return it. Otherwise, this is a spurious RHS token, which we skip. + case tok::r_paren: + if (ParenCount && !isFirstTokenSkipped) + return false; // Matches something. + ConsumeParen(); + break; + case tok::r_square: + if (BracketCount && !isFirstTokenSkipped) + return false; // Matches something. + ConsumeBracket(); + break; + case tok::r_brace: + if (BraceCount && !isFirstTokenSkipped) + return false; // Matches something. + ConsumeBrace(); + break; + + case tok::string_literal: + case tok::wide_string_literal: + ConsumeStringToken(); + break; + case tok::semi: + if (StopAtSemi) + return false; + // FALL THROUGH. + default: + // Skip this token. + ConsumeToken(); + break; + } + isFirstTokenSkipped = false; + } +} + +//===----------------------------------------------------------------------===// +// Scope manipulation +//===----------------------------------------------------------------------===// + +/// EnterScope - Start a new scope. +void Parser::EnterScope(unsigned ScopeFlags) { + if (NumCachedScopes) { + Scope *N = ScopeCache[--NumCachedScopes]; + N->Init(CurScope, ScopeFlags); + CurScope = N; + } else { + CurScope = new Scope(CurScope, ScopeFlags); + } +} + +/// ExitScope - Pop a scope off the scope stack. +void Parser::ExitScope() { + assert(CurScope && "Scope imbalance!"); + + // Inform the actions module that this scope is going away if there are any + // decls in it. + if (!CurScope->decl_empty()) + Actions.ActOnPopScope(Tok.getLocation(), CurScope); + + Scope *OldScope = CurScope; + CurScope = OldScope->getParent(); + + if (NumCachedScopes == ScopeCacheSize) + delete OldScope; + else + ScopeCache[NumCachedScopes++] = OldScope; +} + + + + +//===----------------------------------------------------------------------===// +// C99 6.9: External Definitions. +//===----------------------------------------------------------------------===// + +Parser::~Parser() { + // If we still have scopes active, delete the scope tree. + delete CurScope; + + // Free the scope cache. + for (unsigned i = 0, e = NumCachedScopes; i != e; ++i) + delete ScopeCache[i]; +} + +/// Initialize - Warm up the parser. +/// +void Parser::Initialize() { + // Prime the lexer look-ahead. + ConsumeToken(); + + // Create the translation unit scope. Install it as the current scope. + assert(CurScope == 0 && "A scope is already active?"); + EnterScope(Scope::DeclScope); + Actions.ActOnTranslationUnitScope(Tok.getLocation(), CurScope); + + if (Tok.is(tok::eof) && + !getLang().CPlusPlus) // Empty source file is an extension in C + Diag(Tok, diag::ext_empty_source_file); + + // Initialization for Objective-C context sensitive keywords recognition. + // Referenced in Parser::ParseObjCTypeQualifierList. + if (getLang().ObjC1) { + ObjCTypeQuals[objc_in] = &PP.getIdentifierTable().get("in"); + ObjCTypeQuals[objc_out] = &PP.getIdentifierTable().get("out"); + ObjCTypeQuals[objc_inout] = &PP.getIdentifierTable().get("inout"); + ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway"); + ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy"); + ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); + } + if (getLang().ObjC2) { + ObjCPropertyAttrs[objc_readonly] = &PP.getIdentifierTable().get("readonly"); + ObjCPropertyAttrs[objc_getter] = &PP.getIdentifierTable().get("getter"); + ObjCPropertyAttrs[objc_setter] = &PP.getIdentifierTable().get("setter"); + ObjCPropertyAttrs[objc_assign] = &PP.getIdentifierTable().get("assign"); + ObjCPropertyAttrs[objc_readwrite] = + &PP.getIdentifierTable().get("readwrite"); + ObjCPropertyAttrs[objc_retain] = &PP.getIdentifierTable().get("retain"); + ObjCPropertyAttrs[objc_copy] = &PP.getIdentifierTable().get("copy"); + ObjCPropertyAttrs[objc_nonatomic] = + &PP.getIdentifierTable().get("nonatomic"); + ObjCForCollectionInKW = &PP.getIdentifierTable().get("in"); + } +} + +/// ParseTopLevelDecl - Parse one top-level declaration, return whatever the +/// action tells us to. This returns true if the EOF was encountered. +bool Parser::ParseTopLevelDecl(DeclTy*& Result) { + Result = 0; + if (Tok.is(tok::eof)) return true; + + Result = ParseExternalDeclaration(); + return false; +} + +/// Finalize - Shut down the parser. +/// +void Parser::Finalize() { + ExitScope(); + assert(CurScope == 0 && "Scope imbalance!"); +} + +/// ParseTranslationUnit: +/// translation-unit: [C99 6.9] +/// external-declaration +/// translation-unit external-declaration +void Parser::ParseTranslationUnit() { + Initialize(); + + DeclTy *Res; + while (!ParseTopLevelDecl(Res)) + /*parse them all*/; + + Finalize(); +} + +/// ParseExternalDeclaration: +/// external-declaration: [C99 6.9] +/// function-definition +/// declaration +/// [EXT] ';' +/// [GNU] asm-definition +/// [GNU] __extension__ external-declaration +/// [OBJC] objc-class-definition +/// [OBJC] objc-class-declaration +/// [OBJC] objc-alias-declaration +/// [OBJC] objc-protocol-definition +/// [OBJC] objc-method-definition +/// [OBJC] @end +/// +/// [GNU] asm-definition: +/// simple-asm-expr ';' +/// +Parser::DeclTy *Parser::ParseExternalDeclaration() { + switch (Tok.getKind()) { + case tok::semi: + Diag(Tok, diag::ext_top_level_semi); + ConsumeToken(); + // TODO: Invoke action for top-level semicolon. + return 0; + case tok::kw___extension__: { + ConsumeToken(); + // FIXME: Disable extension warnings. + DeclTy *RV = ParseExternalDeclaration(); + // FIXME: Restore extension warnings. + return RV; + } + case tok::kw_asm: { + ExprResult Result = ParseSimpleAsm(); + + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, + "top-level asm block"); + + if (!Result.isInvalid) + return Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), Result.Val); + } + case tok::at: + // @ is not a legal token unless objc is enabled, no need to check. + return ParseObjCAtDirectives(); + case tok::minus: + case tok::plus: + if (getLang().ObjC1) + return ParseObjCMethodDefinition(); + else { + Diag(Tok, diag::err_expected_external_declaration); + ConsumeToken(); + } + return 0; + case tok::kw_namespace: + case tok::kw_typedef: + // A function definition cannot start with a these keywords. + return ParseDeclaration(Declarator::FileContext); + default: + // We can't tell whether this is a function-definition or declaration yet. + return ParseDeclarationOrFunctionDefinition(); + } +} + +/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or +/// a declaration. We can't tell which we have until we read up to the +/// compound-statement in function-definition. +/// +/// function-definition: [C99 6.9.1] +/// declaration-specifiers[opt] declarator declaration-list[opt] +/// compound-statement +/// declaration: [C99 6.7] +/// declaration-specifiers init-declarator-list[opt] ';' +/// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] +/// [OMP] threadprivate-directive [TODO] +/// +Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { + // Parse the common declaration-specifiers piece. + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" + // declaration-specifiers init-declarator-list[opt] ';' + if (Tok.is(tok::semi)) { + ConsumeToken(); + return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + } + + // ObjC2 allows prefix attributes on class interfaces. + if (getLang().ObjC2 && Tok.is(tok::at)) { + SourceLocation AtLoc = ConsumeToken(); // the "@" + if (!Tok.isObjCAtKeyword(tok::objc_interface)) { + Diag(Tok, diag::err_objc_expected_property_attr);//FIXME:better diagnostic + SkipUntil(tok::semi); // FIXME: better skip? + return 0; + } + const char *PrevSpec = 0; + if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec)) + Diag(AtLoc, diag::err_invalid_decl_spec_combination, PrevSpec); + return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); + } + + // If the declspec consisted only of 'extern' and we have a string + // literal following it, this must be a C++ linkage specifier like + // 'extern "C"'. + if (Tok.is(tok::string_literal) && getLang().CPlusPlus && + DS.getStorageClassSpec() == DeclSpec::SCS_extern && + DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) + return ParseLinkage(Declarator::FileContext); + + // Parse the first declarator. + Declarator DeclaratorInfo(DS, Declarator::FileContext); + ParseDeclarator(DeclaratorInfo); + // Error parsing the declarator? + if (DeclaratorInfo.getIdentifier() == 0) { + // If so, skip until the semi-colon or a }. + SkipUntil(tok::r_brace, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return 0; + } + + // If the declarator is the start of a function definition, handle it. + if (Tok.is(tok::equal) || // int X()= -> not a function def + Tok.is(tok::comma) || // int X(), -> not a function def + Tok.is(tok::semi) || // int X(); -> not a function def + Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def + Tok.is(tok::kw___attribute)) { // int X() __attr__ -> not a function def + // FALL THROUGH. + } else if (DeclaratorInfo.isFunctionDeclarator() && + (Tok.is(tok::l_brace) || // int X() {} + isDeclarationSpecifier())) { // int X(f) int f; {} + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); + + if (Tok.is(tok::l_brace)) { + // This recovery skips the entire function body. It would be nice + // to simply call ParseFunctionDefintion() below, however Sema + // assumes the declarator represents a function, not a typedef. + ConsumeBrace(); + SkipUntil(tok::r_brace, true); + } else { + SkipUntil(tok::semi); + } + return 0; + } + return ParseFunctionDefinition(DeclaratorInfo); + } else { + if (DeclaratorInfo.isFunctionDeclarator()) + Diag(Tok, diag::err_expected_fn_body); + else + Diag(Tok, diag::err_expected_after_declarator); + SkipUntil(tok::semi); + return 0; + } + + // Parse the init-declarator-list for a normal declaration. + return ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); +} + +/// ParseFunctionDefinition - We parsed and verified that the specified +/// Declarator is well formed. If this is a K&R-style function, read the +/// parameters declaration-list, then start the compound-statement. +/// +/// declaration-specifiers[opt] declarator declaration-list[opt] +/// compound-statement [TODO] +/// +Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) { + const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); + assert(FnTypeInfo.Kind == DeclaratorChunk::Function && + "This isn't a function declarator!"); + const DeclaratorChunk::FunctionTypeInfo &FTI = FnTypeInfo.Fun; + + // If this declaration was formed with a K&R-style identifier list for the + // arguments, parse declarations for all of the args next. + // int foo(a,b) int a; float b; {} + if (!FTI.hasPrototype && FTI.NumArgs != 0) + ParseKNRParamDeclarations(D); + + // We should have an opening brace now. + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_fn_body); + + // Skip over garbage, until we get to '{'. Don't eat the '{'. + SkipUntil(tok::l_brace, true, true); + + // If we didn't find the '{', bail out. + if (Tok.isNot(tok::l_brace)) + return 0; + } + + SourceLocation BraceLoc = Tok.getLocation(); + + // Enter a scope for the function body. + EnterScope(Scope::FnScope|Scope::DeclScope); + + // Tell the actions module that we have entered a function definition with the + // specified Declarator for the function. + DeclTy *Res = Actions.ActOnStartOfFunctionDef(CurScope, D); + + return ParseFunctionStatementBody(Res, BraceLoc, BraceLoc); +} + +/// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides +/// types for a function with a K&R-style identifier list for arguments. +void Parser::ParseKNRParamDeclarations(Declarator &D) { + // We know that the top-level of this declarator is a function. + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + // Read all the argument declarations. + while (isDeclarationSpecifier()) { + SourceLocation DSStart = Tok.getLocation(); + + // Parse the common declaration-specifiers piece. + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + + // C99 6.9.1p6: 'each declaration in the declaration list shall have at + // least one declarator'. + // NOTE: GCC just makes this an ext-warn. It's not clear what it does with + // the declarations though. It's trivial to ignore them, really hard to do + // anything else with them. + if (Tok.is(tok::semi)) { + Diag(DSStart, diag::err_declaration_does_not_declare_param); + ConsumeToken(); + continue; + } + + // C99 6.9.1p6: Declarations shall contain no storage-class specifiers other + // than register. + if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && + DS.getStorageClassSpec() != DeclSpec::SCS_register) { + Diag(DS.getStorageClassSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + if (DS.isThreadSpecified()) { + Diag(DS.getThreadSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + + // Parse the first declarator attached to this declspec. + Declarator ParmDeclarator(DS, Declarator::KNRTypeListContext); + ParseDeclarator(ParmDeclarator); + + // Handle the full declarator list. + while (1) { + DeclTy *AttrList; + // If attributes are present, parse them. + if (Tok.is(tok::kw___attribute)) + // FIXME: attach attributes too. + AttrList = ParseAttributes(); + + // Ask the actions module to compute the type for this declarator. + Action::TypeResult TR = + Actions.ActOnParamDeclaratorType(CurScope, ParmDeclarator); + + if (!TR.isInvalid && + // A missing identifier has already been diagnosed. + ParmDeclarator.getIdentifier()) { + + // Scan the argument list looking for the correct param to apply this + // type. + for (unsigned i = 0; ; ++i) { + // C99 6.9.1p6: those declarators shall declare only identifiers from + // the identifier list. + if (i == FTI.NumArgs) { + Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param, + ParmDeclarator.getIdentifier()->getName()); + break; + } + + if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) { + // Reject redefinitions of parameters. + if (FTI.ArgInfo[i].TypeInfo) { + Diag(ParmDeclarator.getIdentifierLoc(), + diag::err_param_redefinition, + ParmDeclarator.getIdentifier()->getName()); + } else { + FTI.ArgInfo[i].TypeInfo = TR.Val; + } + break; + } + } + } + + // If we don't have a comma, it is either the end of the list (a ';') or + // an error, bail out. + if (Tok.isNot(tok::comma)) + break; + + // Consume the comma. + ConsumeToken(); + + // Parse the next declarator. + ParmDeclarator.clear(); + ParseDeclarator(ParmDeclarator); + } + + if (Tok.is(tok::semi)) { + ConsumeToken(); + } else { + Diag(Tok, diag::err_parse_error); + // Skip to end of block or statement + SkipUntil(tok::semi, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + } + + // The actions module must verify that all arguments were declared. +} + + +/// ParseAsmStringLiteral - This is just a normal string-literal, but is not +/// allowed to be a wide string, and is not subject to character translation. +/// +/// [GNU] asm-string-literal: +/// string-literal +/// +Parser::ExprResult Parser::ParseAsmStringLiteral() { + if (!isTokenStringLiteral()) { + Diag(Tok, diag::err_expected_string_literal); + return true; + } + + ExprResult Res = ParseStringLiteralExpression(); + if (Res.isInvalid) return true; + + // TODO: Diagnose: wide string literal in 'asm' + + return Res; +} + +/// ParseSimpleAsm +/// +/// [GNU] simple-asm-expr: +/// 'asm' '(' asm-string-literal ')' +/// +Parser::ExprResult Parser::ParseSimpleAsm() { + assert(Tok.is(tok::kw_asm) && "Not an asm!"); + SourceLocation Loc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after, "asm"); + return 0; + } + + ConsumeParen(); + + ExprResult Result = ParseAsmStringLiteral(); + + MatchRHSPunctuation(tok::r_paren, Loc); + + return Result; +} + diff --git a/clang/lib/Rewrite/Makefile b/clang/lib/Rewrite/Makefile new file mode 100644 index 00000000000..3c0b5a57274 --- /dev/null +++ b/clang/lib/Rewrite/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements code transformation / rewriting facilities. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangRewrite +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp new file mode 100644 index 00000000000..440d1d39fd5 --- /dev/null +++ b/clang/lib/Rewrite/Rewriter.cpp @@ -0,0 +1,258 @@ +//===--- Rewriter.cpp - Code rewriting interface --------------------------===// +// +// 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 Rewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Rewrite/Rewriter.h" +#include "clang/AST/Stmt.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" +#include +using namespace clang; + +/// getMappedOffset - Given an offset into the original SourceBuffer that this +/// RewriteBuffer is based on, map it into the offset space of the +/// RewriteBuffer. +unsigned RewriteBuffer::getMappedOffset(unsigned OrigOffset, + bool AfterInserts) const { + unsigned ResultOffset = OrigOffset; + unsigned DeltaIdx = 0; + + // Move past any deltas that are relevant. + // FIXME: binary search. + for (; DeltaIdx != Deltas.size() && + Deltas[DeltaIdx].FileLoc < OrigOffset; ++DeltaIdx) + ResultOffset += Deltas[DeltaIdx].Delta; + + if (AfterInserts && DeltaIdx != Deltas.size() && + OrigOffset == Deltas[DeltaIdx].FileLoc) + ResultOffset += Deltas[DeltaIdx].Delta; + return ResultOffset; +} + +/// AddDelta - When a change is made that shifts around the text buffer, this +/// method is used to record that info. +void RewriteBuffer::AddDelta(unsigned OrigOffset, int Change) { + assert(Change != 0 && "Not changing anything"); + unsigned DeltaIdx = 0; + + // Skip over any unrelated deltas. + for (; DeltaIdx != Deltas.size() && + Deltas[DeltaIdx].FileLoc < OrigOffset; ++DeltaIdx) + ; + + // If there is no a delta for this offset, insert a new delta record. + if (DeltaIdx == Deltas.size() || OrigOffset != Deltas[DeltaIdx].FileLoc) { + // If this is a removal, check to see if this can be folded into + // a delta at the end of the deletion. For example, if we have: + // ABCXDEF (X inserted after C) and delete C, we want to end up with no + // delta because X basically replaced C. + if (Change < 0 && DeltaIdx != Deltas.size() && + OrigOffset-Change == Deltas[DeltaIdx].FileLoc) { + // Adjust the start of the delta to be the start of the deleted region. + Deltas[DeltaIdx].FileLoc += Change; + Deltas[DeltaIdx].Delta += Change; + + // If the delta becomes a noop, remove it. + if (Deltas[DeltaIdx].Delta == 0) + Deltas.erase(Deltas.begin()+DeltaIdx); + return; + } + + // Otherwise, create an entry and return. + Deltas.insert(Deltas.begin()+DeltaIdx, + SourceDelta::get(OrigOffset, Change)); + return; + } + + // Otherwise, we found a delta record at this offset, adjust it. + Deltas[DeltaIdx].Delta += Change; + + // If it is now dead, remove it. + if (Deltas[DeltaIdx].Delta == 0) + Deltas.erase(Deltas.begin()+DeltaIdx); +} + + +void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { + // Nothing to remove, exit early. + if (Size == 0) return; + + unsigned RealOffset = getMappedOffset(OrigOffset, true); + assert(RealOffset+Size < Buffer.size() && "Invalid location"); + + // Remove the dead characters. + RewriteRope::iterator I = Buffer.getAtOffset(RealOffset); + Buffer.erase(I, I+Size); + + // Add a delta so that future changes are offset correctly. + AddDelta(OrigOffset, -Size); +} + +void RewriteBuffer::InsertText(unsigned OrigOffset, + const char *StrData, unsigned StrLen) { + // Nothing to insert, exit early. + if (StrLen == 0) return; + + unsigned RealOffset = getMappedOffset(OrigOffset, true); + assert(RealOffset <= Buffer.size() && "Invalid location"); + + // Insert the new characters. + Buffer.insert(Buffer.getAtOffset(RealOffset), StrData, StrData+StrLen); + + // Add a delta so that future changes are offset correctly. + AddDelta(OrigOffset, StrLen); +} + +/// ReplaceText - This method replaces a range of characters in the input +/// buffer with a new string. This is effectively a combined "remove/insert" +/// operation. +void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, + const char *NewStr, unsigned NewLength) { + unsigned RealOffset = getMappedOffset(OrigOffset, true); + assert(RealOffset+OrigLength <= Buffer.size() && "Invalid location"); + + // Overwrite the common piece. + unsigned CommonLength = std::min(OrigLength, NewLength); + std::copy(NewStr, NewStr+CommonLength, Buffer.getAtOffset(RealOffset)); + + // If replacing without shifting around, just overwrite the text. + if (OrigLength == NewLength) + return; + + // If inserting more than existed before, this is like an insertion. + if (NewLength > OrigLength) { + Buffer.insert(Buffer.getAtOffset(RealOffset+OrigLength), + NewStr+OrigLength, NewStr+NewLength); + } else { + // If inserting less than existed before, this is like a removal. + RewriteRope::iterator I = Buffer.getAtOffset(RealOffset+NewLength); + Buffer.erase(I, I+(OrigLength-NewLength)); + } + AddDelta(OrigOffset, NewLength-OrigLength); +} + + +//===----------------------------------------------------------------------===// +// Rewriter class +//===----------------------------------------------------------------------===// + +/// getRangeSize - Return the size in bytes of the specified range if they +/// are in the same file. If not, this returns -1. +int Rewriter::getRangeSize(SourceRange Range) const { + if (!isRewritable(Range.getBegin()) || + !isRewritable(Range.getEnd())) return -1; + + unsigned StartOff, StartFileID; + unsigned EndOff , EndFileID; + + StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); + EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); + + if (StartFileID != EndFileID) + return -1; + + // If edits have been made to this buffer, the delta between the range may + // have changed. + std::map::const_iterator I = + RewriteBuffers.find(StartFileID); + if (I != RewriteBuffers.end()) { + const RewriteBuffer &RB = I->second; + EndOff = RB.getMappedOffset(EndOff, true); + StartOff = RB.getMappedOffset(StartOff); + } + + + // Adjust the end offset to the end of the last token, instead of being the + // start of the last token. + EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr); + + return EndOff-StartOff; +} + + +unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, + unsigned &FileID) const { + std::pair V = SourceMgr->getDecomposedFileLoc(Loc); + FileID = V.first; + return V.second; +} + + +/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. +/// +RewriteBuffer &Rewriter::getEditBuffer(unsigned FileID) { + std::map::iterator I = + RewriteBuffers.lower_bound(FileID); + if (I != RewriteBuffers.end() && I->first == FileID) + return I->second; + I = RewriteBuffers.insert(I, std::make_pair(FileID, RewriteBuffer())); + + std::pair MB = SourceMgr->getBufferData(FileID); + I->second.Initialize(MB.first, MB.second); + + return I->second; +} + +/// InsertText - Insert the specified string at the specified location in the +/// original buffer. +bool Rewriter::InsertText(SourceLocation Loc, + const char *StrData, unsigned StrLen) { + if (!isRewritable(Loc)) return true; + unsigned FileID; + unsigned StartOffs = getLocationOffsetAndFileID(Loc, FileID); + getEditBuffer(FileID).InsertText(StartOffs, StrData, StrLen); + return false; +} + +/// RemoveText - Remove the specified text region. +bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) { + if (!isRewritable(Start)) return true; + unsigned FileID; + unsigned StartOffs = getLocationOffsetAndFileID(Start, FileID); + getEditBuffer(FileID).RemoveText(StartOffs, Length); + return false; +} + +/// ReplaceText - This method replaces a range of characters in the input +/// buffer with a new string. This is effectively a combined "remove/insert" +/// operation. +bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, + const char *NewStr, unsigned NewLength) { + if (!isRewritable(Start)) return true; + unsigned StartFileID; + unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); + + getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, + NewStr, NewLength); + return false; +} + +/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty +/// printer to generate the replacement code. This returns true if the input +/// could not be rewritten, or false if successful. +bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { + // Measaure the old text. + int Size = getRangeSize(From->getSourceRange()); + if (Size == -1) + return true; + + // Get the new text. + std::ostringstream S; + To->printPretty(S); + const std::string &Str = S.str(); + + ReplaceText(From->getLocStart(), Size, &Str[0], Str.size()); + return false; +} + + diff --git a/clang/lib/Sema/Makefile b/clang/lib/Sema/Makefile new file mode 100644 index 00000000000..19a00275f0f --- /dev/null +++ b/clang/lib/Sema/Makefile @@ -0,0 +1,23 @@ +##===- clang/lib/Sema/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the semantic analyzer and AST builder library for the +# C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangSEMA +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Sema/ParseAST.cpp b/clang/lib/Sema/ParseAST.cpp new file mode 100644 index 00000000000..364b0729100 --- /dev/null +++ b/clang/lib/Sema/ParseAST.cpp @@ -0,0 +1,69 @@ +//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/ParseAST.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" +#include "Sema.h" +#include "clang/Parse/Action.h" +#include "clang/Parse/Parser.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Public interface to the file +//===----------------------------------------------------------------------===// + +/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as +/// the file is parsed. This takes ownership of the ASTConsumer and +/// ultimately deletes it. +void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, bool PrintStats) { + // Collect global stats on Decls/Stmts (until we have a module streamer). + if (PrintStats) { + Decl::CollectingStats(true); + Stmt::CollectingStats(true); + } + + ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(), + PP.getIdentifierTable(), PP.getSelectorTable()); + + Parser P(PP, *new Sema(PP, Context, *Consumer)); + PP.EnterMainSourceFile(); + + // Initialize the parser. + P.Initialize(); + + Consumer->Initialize(Context); + + Parser::DeclTy *ADecl; + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl) + Consumer->HandleTopLevelDecl(static_cast(ADecl)); + }; + + if (PrintStats) { + fprintf(stderr, "\nSTATISTICS:\n"); + P.getActions().PrintStats(); + Context.PrintStats(); + Decl::PrintStats(); + Stmt::PrintStats(); + Consumer->PrintStats(); + + Decl::CollectingStats(false); + Stmt::CollectingStats(false); + } + + delete Consumer; +} diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp new file mode 100644 index 00000000000..4bd04e3a1a5 --- /dev/null +++ b/clang/lib/Sema/Sema.cpp @@ -0,0 +1,222 @@ +//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the actions class which performs semantic analysis and +// builds an AST out of a parse stream. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Parse/Scope.h" + +using namespace clang; + +bool Sema::isBuiltinObjCType(TypedefDecl *TD) { + const char *typeName = TD->getIdentifier()->getName(); + return strcmp(typeName, "id") == 0 || strcmp(typeName, "Class") == 0 || + strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0; +} + +bool Sema::isObjCObjectPointerType(QualType type) const { + if (!type->isPointerType() && !type->isObjCQualifiedIdType()) + return false; + if (type == Context.getObjCIdType() || type == Context.getObjCClassType() || + type->isObjCQualifiedIdType()) + return true; + + if (type->isPointerType()) { + PointerType *pointerType = static_cast(type.getTypePtr()); + type = pointerType->getPointeeType(); + } + return (type->isObjCInterfaceType() || type->isObjCQualifiedIdType()); +} + +void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { + TUScope = S; + if (!PP.getLangOptions().ObjC1) return; + + TypedefType *t; + + // Add the built-in ObjC types. + t = cast(Context.getObjCIdType().getTypePtr()); + t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); + TUScope->AddDecl(t->getDecl()); + t = cast(Context.getObjCClassType().getTypePtr()); + t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl()); + TUScope->AddDecl(t->getDecl()); + ObjCInterfaceType *it = cast(Context.getObjCProtoType()); + ObjCInterfaceDecl *IDecl = it->getDecl(); + IDecl->getIdentifier()->setFETokenInfo(IDecl); + TUScope->AddDecl(IDecl); + + // Synthesize "typedef struct objc_selector *SEL;" + RecordDecl *SelTag = RecordDecl::Create(Context, Decl::Struct, + SourceLocation(), + &Context.Idents.get("objc_selector"), + 0); + SelTag->getIdentifier()->setFETokenInfo(SelTag); + TUScope->AddDecl(SelTag); + + QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); + TypedefDecl *SelTypedef = TypedefDecl::Create(Context, SourceLocation(), + &Context.Idents.get("SEL"), + SelT, 0); + SelTypedef->getIdentifier()->setFETokenInfo(SelTypedef); + TUScope->AddDecl(SelTypedef); + Context.setObjCSelType(SelTypedef); +} + +Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer) + : PP(pp), Context(ctxt), Consumer(consumer), + CurFunctionDecl(0), CurMethodDecl(0) { + + // Get IdentifierInfo objects for known functions for which we + // do extra checking. + IdentifierTable &IT = PP.getIdentifierTable(); + + KnownFunctionIDs[id_printf] = &IT.get("printf"); + KnownFunctionIDs[id_fprintf] = &IT.get("fprintf"); + KnownFunctionIDs[id_sprintf] = &IT.get("sprintf"); + KnownFunctionIDs[id_snprintf] = &IT.get("snprintf"); + KnownFunctionIDs[id_asprintf] = &IT.get("asprintf"); + KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf"); + KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf"); + KnownFunctionIDs[id_vfprintf] = &IT.get("vfprintf"); + KnownFunctionIDs[id_vsprintf] = &IT.get("vsprintf"); + KnownFunctionIDs[id_vprintf] = &IT.get("vprintf"); + + // FIXME: Move this initialization up to Sema::ActOnTranslationUnitScope() + // and make sure the decls get inserted into TUScope! + if (PP.getLangOptions().ObjC1) { + // Synthesize "typedef struct objc_class *Class;" + RecordDecl *ClassTag = RecordDecl::Create(Context, Decl::Struct, + SourceLocation(), + &IT.get("objc_class"), 0); + QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); + TypedefDecl *ClassTypedef = + TypedefDecl::Create(Context, SourceLocation(), + &Context.Idents.get("Class"), ClassT, 0); + Context.setObjCClassType(ClassTypedef); + + // Synthesize "@class Protocol; + ObjCInterfaceDecl *ProtocolDecl = new ObjCInterfaceDecl(SourceLocation(), 0, + &Context.Idents.get("Protocol"), true); + Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); + + // Synthesize "typedef struct objc_object { Class isa; } *id;" + RecordDecl *ObjectTag = + RecordDecl::Create(Context, Decl::Struct, SourceLocation(), + &IT.get("objc_object"), 0); + FieldDecl *IsaDecl = new FieldDecl(SourceLocation(), 0, + Context.getObjCClassType()); + ObjectTag->defineBody(&IsaDecl, 1); + QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); + TypedefDecl *IdTypedef = TypedefDecl::Create(Context, SourceLocation(), + &Context.Idents.get("id"), + ObjT, 0); + Context.setObjCIdType(IdTypedef); + } + TUScope = 0; +} + +/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. +/// If there is already an implicit cast, merge into the existing one. +void Sema::ImpCastExprToType(Expr *&Expr, QualType Type) { + if (Expr->getType().getCanonicalType() == Type.getCanonicalType()) return; + + if (ImplicitCastExpr *ImpCast = dyn_cast(Expr)) + ImpCast->setType(Type); + else + Expr = new ImplicitCastExpr(Type, Expr); +} + + + +void Sema::DeleteExpr(ExprTy *E) { + delete static_cast(E); +} +void Sema::DeleteStmt(StmtTy *S) { + delete static_cast(S); +} + +//===----------------------------------------------------------------------===// +// Helper functions. +//===----------------------------------------------------------------------===// + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID) { + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) { + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2) { + std::string MsgArr[] = { Msg1, Msg2 }; + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) { + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, &Range,1); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, + SourceRange Range) { + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, &Range,1); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2, SourceRange Range) { + std::string MsgArr[] = { Msg1, Msg2 }; + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2, &Range, 1); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2, const std::string &Msg3, + SourceRange R1) { + std::string MsgArr[] = { Msg1, Msg2, Msg3 }; + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 3, &R1, 1); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, + SourceRange R1, SourceRange R2) { + SourceRange RangeArr[] = { R1, R2 }; + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, RangeArr, 2); + return true; +} + +bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, + SourceRange R1, SourceRange R2) { + SourceRange RangeArr[] = { R1, R2 }; + PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, RangeArr, 2); + return true; +} + +bool Sema::Diag(SourceLocation Range, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2, SourceRange R1, SourceRange R2) { + std::string MsgArr[] = { Msg1, Msg2 }; + SourceRange RangeArr[] = { R1, R2 }; + PP.getDiagnostics().Report(PP.getFullLoc(Range),DiagID, MsgArr,2,RangeArr, 2); + return true; +} + +const LangOptions &Sema::getLangOptions() const { + return PP.getLangOptions(); +} diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h new file mode 100644 index 00000000000..fc81781911c --- /dev/null +++ b/clang/lib/Sema/Sema.h @@ -0,0 +1,823 @@ +//===--- Sema.h - Semantic Analysis & AST Building --------------*- 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 Sema class, which performs semantic analysis and +// builds ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_SEMA_H +#define LLVM_CLANG_AST_SEMA_H + +#include "clang/Parse/Action.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include +#include + +namespace llvm { + class APSInt; +} + +namespace clang { + class ASTContext; + class ASTConsumer; + class Preprocessor; + class Decl; + class ScopedDecl; + class Expr; + class InitListExpr; + class CallExpr; + class VarDecl; + class ParmVarDecl; + class TypedefDecl; + class FunctionDecl; + class QualType; + struct LangOptions; + class Token; + class IntegerLiteral; + class StringLiteral; + class ArrayType; + class LabelStmt; + class SwitchStmt; + class OCUVectorType; + class TypedefDecl; + class ObjCInterfaceDecl; + class ObjCProtocolDecl; + class ObjCImplementationDecl; + class ObjCCategoryImplDecl; + class ObjCCategoryDecl; + class ObjCIvarDecl; + class ObjCMethodDecl; + +/// Sema - This implements semantic analysis and AST building for C. +class Sema : public Action { + Preprocessor &PP; + ASTContext &Context; + ASTConsumer &Consumer; + + /// CurFunctionDecl - If inside of a function body, this contains a pointer to + /// the function decl for the function being parsed. + FunctionDecl *CurFunctionDecl; + + /// CurMethodDecl - If inside of a method body, this contains a pointer to + /// the method decl for the method being parsed. + ObjCMethodDecl *CurMethodDecl; + + /// LabelMap - This is a mapping from label identifiers to the LabelStmt for + /// it (which acts like the label decl in some ways). Forward referenced + /// labels have a LabelStmt created for them with a null location & SubStmt. + llvm::DenseMap LabelMap; + + llvm::SmallVector SwitchStack; + + /// OCUVectorDecls - This is a list all the OCU vector types. This allows + /// us to associate a raw vector type with one of the OCU type names. + /// This is only necessary for issuing pretty diagnostics. + llvm::SmallVector OCUVectorDecls; + + /// ObjCImplementations - Keep track of all of the classes with + /// @implementation's, so that we can emit errors on duplicates. + llvm::DenseMap ObjCImplementations; + + /// ObjCProtocols - Keep track of all protocol declarations declared + /// with @protocol keyword, so that we can emit errors on duplicates and + /// find the declarations when needed. + llvm::DenseMap ObjCProtocols; + + // Enum values used by KnownFunctionIDs (see below). + enum { + id_printf, + id_fprintf, + id_sprintf, + id_snprintf, + id_asprintf, + id_vsnprintf, + id_vasprintf, + id_vfprintf, + id_vsprintf, + id_vprintf, + id_num_known_functions + }; + + /// KnownFunctionIDs - This is a list of IdentifierInfo objects to a set + /// of known functions used by the semantic analysis to do various + /// kinds of checking (e.g. checking format string errors in printf calls). + /// This list is populated upon the creation of a Sema object. + IdentifierInfo* KnownFunctionIDs[ id_num_known_functions ]; + + /// Translation Unit Scope - useful to Objective-C actions that need + /// to lookup file scope declarations in the "ordinary" C decl namespace. + /// For example, user-defined classes, built-in "id" type, etc. + Scope *TUScope; + + /// ObjCMethodList - a linked list of methods with different signatures. + struct ObjCMethodList { + ObjCMethodDecl *Method; + ObjCMethodList *Next; + + ObjCMethodList() { + Method = 0; + Next = 0; + } + ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { + Method = M; + Next = C; + } + }; + /// Instance/Factory Method Pools - allows efficient lookup when typechecking + /// messages to "id". We need to maintain a list, since selectors can have + /// differing signatures across classes. In Cocoa, this happens to be + /// extremely uncommon (only 1% of selectors are "overloaded"). + llvm::DenseMap InstanceMethodPool; + llvm::DenseMap FactoryMethodPool; +public: + Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer); + + const LangOptions &getLangOptions() const; + + /// The primitive diagnostic helpers - always returns true, which simplifies + /// error handling (i.e. less code). + bool Diag(SourceLocation Loc, unsigned DiagID); + bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg); + bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2); + + /// More expressive diagnostic helpers for expressions (say that 6 times:-) + bool Diag(SourceLocation Loc, unsigned DiagID, SourceRange R1); + bool Diag(SourceLocation Loc, unsigned DiagID, + SourceRange R1, SourceRange R2); + bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, + SourceRange R1); + bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg, + SourceRange R1, SourceRange R2); + bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2, SourceRange R1); + bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1, + const std::string &Msg2, const std::string &Msg3, SourceRange R1); + bool Diag(SourceLocation Loc, unsigned DiagID, + const std::string &Msg1, const std::string &Msg2, + SourceRange R1, SourceRange R2); + + virtual void DeleteExpr(ExprTy *E); + virtual void DeleteStmt(StmtTy *S); + + //===--------------------------------------------------------------------===// + // Type Analysis / Processing: SemaType.cpp. + // + QualType ConvertDeclSpecToType(DeclSpec &DS); + AttributeList *ProcessTypeAttributes(QualType &Result, AttributeList *AL); + QualType GetTypeForDeclarator(Declarator &D, Scope *S); + + + QualType ObjCGetTypeForMethodDefinition(DeclTy *D); + + + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); + + virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D); +private: + //===--------------------------------------------------------------------===// + // Symbol table / Decl tracking callbacks: SemaDecl.cpp. + // + virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const; + virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup); + void AddInitializerToDecl(DeclTy *dcl, ExprTy *init); + virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group); + + virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D); + virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D); + + virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body); + virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace, + SourceLocation RBrace, const char *Lang, + unsigned StrSize, DeclTy *D); + virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprTy *expr); + + /// Scope actions. + virtual void ActOnPopScope(SourceLocation Loc, Scope *S); + virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); + + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with + /// no declarator (e.g. "struct foo;") is parsed. + virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); + + virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, + SourceLocation KWLoc, IdentifierInfo *Name, + SourceLocation NameLoc, AttributeList *Attr); + virtual DeclTy *ActOnField(Scope *S, DeclTy *TagDecl,SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth); + + // This is used for both record definitions and ObjC interface declarations. + virtual void ActOnFields(Scope* S, + SourceLocation RecLoc, DeclTy *TagDecl, + DeclTy **Fields, unsigned NumFields, + SourceLocation LBrac, SourceLocation RBrac, + tok::ObjCKeywordKind *visibility = 0); + virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl, + DeclTy *LastEnumConstant, + SourceLocation IdLoc, IdentifierInfo *Id, + SourceLocation EqualLoc, ExprTy *Val); + virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl, + DeclTy **Elements, unsigned NumElements); +private: + /// Subroutines of ActOnDeclarator(). + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + ScopedDecl *LastDecl); + TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *Old); + FunctionDecl *MergeFunctionDecl(FunctionDecl *New, ScopedDecl *Old); + VarDecl *MergeVarDecl(VarDecl *New, ScopedDecl *Old); + + /// More parsing and symbol table subroutines... + ParmVarDecl *ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, + Scope *FnBodyScope); + ScopedDecl *LookupScopedDecl(IdentifierInfo *II, unsigned NSI, + SourceLocation IdLoc, Scope *S); + ScopedDecl *LookupInterfaceDecl(IdentifierInfo *II); + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); + ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S); + ScopedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, + Scope *S); + // Decl attributes - this routine is the top level dispatcher. + void HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix, + AttributeList *declarator_postfix); + void HandleDeclAttribute(Decl *New, AttributeList *rawAttr); + + /// HandleAddressSpaceTypeAttribute - this attribute is only applicable to + /// objects without automatic storage duration. + /// The raw attribute contains 1 argument, the id of the address space + /// for the type. + QualType HandleAddressSpaceTypeAttribute(QualType curType, + AttributeList *rawAttr); + + // HandleVectorTypeAttribute - this attribute is only applicable to + // integral and float scalars, although arrays, pointers, and function + // return values are allowed in conjunction with this construct. Aggregates + // with this attribute are invalid, even if they are of the same size as a + // corresponding scalar. + // The raw attribute should contain precisely 1 argument, the vector size + // for the variable, measured in bytes. If curType and rawAttr are well + // formed, this routine will return a new vector type. + QualType HandleVectorTypeAttribute(QualType curType, AttributeList *rawAttr); + void HandleOCUVectorTypeAttribute(TypedefDecl *d, AttributeList *rawAttr); + + void HandleAlignedAttribute(Decl *d, AttributeList *rawAttr); + void HandlePackedAttribute(Decl *d, AttributeList *rawAttr); + void HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr); + void HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr); + void HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr); + void HandleWeakAttribute(Decl *d, AttributeList *rawAttr); + void HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr); + void HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr); + void HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr); + void HandleNothrowAttribute(Decl *d, AttributeList *rawAttr); + void HandleFormatAttribute(Decl *d, AttributeList *rawAttr); + void HandleStdCallAttribute(Decl *d, AttributeList *rawAttr); + void HandleFastCallAttribute(Decl *d, AttributeList *rawAttr); + + void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, + bool &IncompleteImpl); + + /// CheckProtocolMethodDefs - This routine checks unimpletented methods + /// Declared in protocol, and those referenced by it. + void CheckProtocolMethodDefs(SourceLocation ImpLoc, + ObjCProtocolDecl *PDecl, + bool& IncompleteImpl, + const llvm::DenseSet &InsMap, + const llvm::DenseSet &ClsMap); + + /// CheckImplementationIvars - This routine checks if the instance variables + /// listed in the implelementation match those listed in the interface. + void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **Fields, unsigned nIvars, + SourceLocation Loc); + + /// ImplMethodsVsClassMethods - This is main routine to warn if any method + /// remains unimplemented in the @implementation class. + void ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, + ObjCInterfaceDecl* IDecl); + + /// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the + /// category interface is implemented in the category @implementation. + void ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl, + ObjCCategoryDecl *CatClassDecl); + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns + /// true, or false, accordingly. + bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod); + + /// isBuiltinObjCType - Returns true of the type is "id", "SEL", "Class" + /// or "Protocol". + bool isBuiltinObjCType(TypedefDecl *TD); + + /// isObjCObjectPointerType - Returns true if type is an objective-c pointer + /// to an object type; such as "id", "Class", Intf*, id

, etc. + bool isObjCObjectPointerType(QualType type) const; + + /// AddInstanceMethodToGlobalPool - All instance methods in a translation + /// unit are added to a global pool. This allows us to efficiently associate + /// a selector with a method declaraation for purposes of typechecking + /// messages sent to "id" (where the class of the object is unknown). + void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method); + + /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. + void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); + //===--------------------------------------------------------------------===// + // Statement Parsing Callbacks: SemaStmt.cpp. +public: + virtual StmtResult ActOnExprStmt(ExprTy *Expr); + + virtual StmtResult ActOnNullStmt(SourceLocation SemiLoc); + virtual StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, + StmtTy **Elts, unsigned NumElts, + bool isStmtExpr); + virtual StmtResult ActOnDeclStmt(DeclTy *Decl, SourceLocation StartLoc, + SourceLocation EndLoc); + virtual StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *LHSVal, + SourceLocation DotDotDotLoc, ExprTy *RHSVal, + SourceLocation ColonLoc, StmtTy *SubStmt); + virtual StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, StmtTy *SubStmt, + Scope *CurScope); + virtual StmtResult ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation ColonLoc, StmtTy *SubStmt); + virtual StmtResult ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal, + StmtTy *ThenVal, SourceLocation ElseLoc, + StmtTy *ElseVal); + virtual StmtResult ActOnStartOfSwitchStmt(ExprTy *Cond); + virtual StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + StmtTy *Switch, ExprTy *Body); + virtual StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, + StmtTy *Body); + virtual StmtResult ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body, + SourceLocation WhileLoc, ExprTy *Cond); + + virtual StmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtTy *First, ExprTy *Second, ExprTy *Third, + SourceLocation RParenLoc, StmtTy *Body); + virtual StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, + SourceLocation LParenLoc, + StmtTy *First, ExprTy *Second, + SourceLocation RParenLoc, StmtTy *Body); + + virtual StmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + IdentifierInfo *LabelII); + virtual StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + ExprTy *DestExp); + virtual StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, + Scope *CurScope); + virtual StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope); + + virtual StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, + ExprTy *RetValExp); + + virtual StmtResult ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + std::string *Names, + ExprTy **Constraints, + ExprTy **Exprs, + ExprTy *AsmString, + unsigned NumClobbers, + ExprTy **Clobbers, + SourceLocation RParenLoc); + + virtual StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParen, StmtTy *Parm, + StmtTy *Body, StmtTy *CatchList); + + virtual StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, + StmtTy *Body); + + virtual StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, + StmtTy *Try, + StmtTy *Catch, StmtTy *Finally); + + virtual StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, + StmtTy *Throw); + virtual StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + ExprTy *SynchExpr, + StmtTy *SynchBody); + + //===--------------------------------------------------------------------===// + // Expression Parsing Callbacks: SemaExpr.cpp. + + // Primary Expressions. + virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, + IdentifierInfo &II, + bool HasTrailingLParen); + virtual ExprResult ActOnPreDefinedExpr(SourceLocation Loc, + tok::TokenKind Kind); + virtual ExprResult ActOnNumericConstant(const Token &); + virtual ExprResult ActOnCharacterConstant(const Token &); + virtual ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, + ExprTy *Val); + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks); + + // Binary/Unary Operators. 'Tok' is the token for the operator. + virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, + ExprTy *Input); + virtual ExprResult + ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, + SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc); + + virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc, + tok::TokenKind Kind, ExprTy *Input); + + virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, + ExprTy *Idx, SourceLocation RLoc); + virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + IdentifierInfo &Member); + + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. + /// This provides the location of the left/right parens and a list of comma + /// locations. + virtual ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc, + ExprTy **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + + virtual ExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprTy *Op); + + virtual ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprTy *Op); + + virtual ExprResult ActOnInitList(SourceLocation LParenLoc, + ExprTy **InitList, unsigned NumInit, + SourceLocation RParenLoc); + + virtual ExprResult ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind, + ExprTy *LHS,ExprTy *RHS); + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + virtual ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + ExprTy *Cond, ExprTy *LHS, ExprTy *RHS); + + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". + virtual ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, + IdentifierInfo *LabelII); + + virtual ExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt, + SourceLocation RPLoc); // "({..})" + + /// __builtin_offsetof(type, a.b[123][456].c) + virtual ExprResult ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, + SourceLocation TypeLoc, TypeTy *Arg1, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); + + // __builtin_types_compatible_p(type1, type2) + virtual ExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeTy *arg1, TypeTy *arg2, + SourceLocation RPLoc); + + // __builtin_choose_expr(constExpr, expr1, expr2) + virtual ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + ExprTy *cond, ExprTy *expr1, ExprTy *expr2, + SourceLocation RPLoc); + + // __builtin_overload(...) + virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + + // __builtin_va_arg(expr, type) + virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc, + ExprTy *expr, TypeTy *type, + SourceLocation RPLoc); + + /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. + virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, ExprTy *E, + SourceLocation RParenLoc); + + /// ActOnCXXBoolLiteral - Parse {true,false} literals. + virtual ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, + tok::TokenKind Kind); + + //// ActOnCXXThrow - Parse throw expressions. + virtual ExprResult ActOnCXXThrow(SourceLocation OpLoc, + ExprTy *expr); + + // ParseObjCStringLiteral - Parse Objective-C string literals. + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings); + virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + TypeTy *Ty, + SourceLocation RParenLoc); + + // ParseObjCSelectorExpression - Build selector expression for @selector + virtual ExprResult ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + // ParseObjCProtocolExpression - Build protocol expression for @protocol + virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + // Objective-C declarations. + virtual DeclTy *ActOnStartClassInterface( + SourceLocation AtInterafceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + IdentifierInfo **ProtocolNames, unsigned NumProtocols, + SourceLocation EndProtoLoc, AttributeList *AttrList); + + virtual DeclTy *ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation); + + virtual DeclTy *ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, + IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc); + + virtual DeclTy *ActOnStartCategoryInterface( + SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc); + + virtual DeclTy *ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc); + + virtual DeclTy *ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CatName, + SourceLocation CatLoc); + + virtual DeclTy *ActOnForwardClassDeclaration(SourceLocation Loc, + IdentifierInfo **IdentList, + unsigned NumElts); + + virtual DeclTy *ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, + unsigned NumElts); + + virtual void FindProtocolDeclaration(SourceLocation TypeLoc, + IdentifierInfo **ProtocolId, + unsigned NumProtocols, + llvm::SmallVector & + Protocols); + + virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, + DeclTy **allMethods = 0, unsigned allNum = 0, + DeclTy **allProperties = 0, unsigned pNum = 0); + + virtual DeclTy *ActOnAddObjCProperties(SourceLocation AtLoc, + DeclTy **allProperties, + unsigned NumProperties, + ObjCDeclSpec &DS); + + virtual DeclTy *ActOnMethodDeclaration( + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, + DeclTy *ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, + Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames, + AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, + bool isVariadic = false); + + // ActOnClassMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from NumArgs. + virtual ExprResult ActOnClassMessage( + Scope *S, + IdentifierInfo *receivingClassName, Selector Sel, + SourceLocation lbrac, SourceLocation rbrac, + ExprTy **ArgExprs, unsigned NumArgs); + + // ActOnInstanceMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from NumArgs. + virtual ExprResult ActOnInstanceMessage( + ExprTy *receiver, Selector Sel, + SourceLocation lbrac, SourceLocation rbrac, + ExprTy **ArgExprs, unsigned NumArgs); +private: + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit + /// cast. If there is already an implicit cast, merge into the existing one. + void ImpCastExprToType(Expr *&Expr, QualType Type); + + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts + // functions and arrays to their respective pointers (C99 6.3.2.1). + Expr *UsualUnaryConversions(Expr *&expr); + + // DefaultFunctionArrayConversion - converts functions and arrays + // to their respective pointers (C99 6.3.2.1). + void DefaultFunctionArrayConversion(Expr *&expr); + + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that + // do not have a prototype. Integer promotions are performed on each + // argument, and arguments that have type float are promoted to double. + void DefaultArgumentPromotion(Expr *&Expr); + + // UsualArithmeticConversions - performs the UsualUnaryConversions on it's + // operands and then handles various conversions that are common to binary + // operators (C99 6.3.1.8). If both operands aren't arithmetic, this + // routine returns the first non-arithmetic type found. The client is + // responsible for emitting appropriate error diagnostics. + QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, + bool isCompAssign = false); + + /// AssignConvertType - All of the 'assignment' semantic checks return this + /// enum to indicate whether the assignment was allowed. These checks are + /// done for simple assignments, as well as initialization, return from + /// function, argument passing, etc. The query is phrased in terms of a + /// source and destination type. + enum AssignConvertType { + /// Compatible - the types are compatible according to the standard. + Compatible, + + /// PointerToInt - The assignment converts a pointer to an int, which we + /// accept as an extension. + PointerToInt, + + /// IntToPointer - The assignment converts an int to a pointer, which we + /// accept as an extension. + IntToPointer, + + /// FunctionVoidPointer - The assignment is between a function pointer and + /// void*, which the standard doesn't allow, but we accept as an extension. + FunctionVoidPointer, + + /// IncompatiblePointer - The assignment is between two pointers types that + /// are not compatible, but we accept them as an extension. + IncompatiblePointer, + + /// CompatiblePointerDiscardsQualifiers - The assignment discards + /// c/v/r qualifiers, which we accept as an extension. + CompatiblePointerDiscardsQualifiers, + + /// Incompatible - We reject this conversion outright, it is invalid to + /// represent it in the AST. + Incompatible + }; + + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the + /// assignment conversion type specified by ConvTy. This returns true if the + /// conversion was invalid or false if the conversion was accepted. + bool DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, const char *Flavor); + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. + /// This routine is only used by the following two methods. C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); + + // CheckSingleAssignmentConstraints - Currently used by ActOnCallExpr, + // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, + // this routine performs the default function/array converions. + AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, + Expr *&rExpr); + // CheckCompoundAssignmentConstraints - Type check without performing any + // conversions. For compound assignments, the "Check...Operands" methods + // perform the necessary conversions. + AssignConvertType CheckCompoundAssignmentConstraints(QualType lhs, + QualType rhs); + + // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) + AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, + QualType rhsType); + + /// the following "Check" methods will return a valid/converted QualType + /// or a null QualType (indicating an error diagnostic was issued). + + /// type checking binary operators (subroutines of ActOnBinOp). + inline QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); + inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); + inline QualType CheckMultiplyDivideOperands( // C99 6.5.5 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + inline QualType CheckRemainderOperands( // C99 6.5.5 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + inline QualType CheckAdditionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + inline QualType CheckSubtractionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + inline QualType CheckShiftOperands( // C99 6.5.7 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + inline QualType CheckCompareOperands( // C99 6.5.8/9 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isRelational); + inline QualType CheckBitwiseOperands( // C99 6.5.[10...12] + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + inline QualType CheckLogicalOperands( // C99 6.5.[13,14] + Expr *&lex, Expr *&rex, SourceLocation OpLoc); + // CheckAssignmentOperands is used for both simple and compound assignment. + // For simple assignment, pass both expressions and a null converted type. + // For compound assignment, pass both expressions and the converted type. + inline QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] + Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType); + inline QualType CheckCommaOperands( // C99 6.5.17 + Expr *&lex, Expr *&rex, SourceLocation OpLoc); + inline QualType CheckConditionalOperands( // C99 6.5.15 + Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); + + /// type checking unary operators (subroutines of ActOnUnaryOp). + /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 + QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc); + QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); + QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); + QualType CheckSizeOfAlignOfOperand(QualType type, SourceLocation loc, + bool isSizeof); + QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc); + + /// type checking primary expressions. + QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc, + IdentifierInfo &Comp, SourceLocation CmpLoc); + + /// type checking declaration initializers (C99 6.7.8) + bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType); + bool CheckSingleInitializer(Expr *&simpleInit, QualType declType); + bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, + QualType ElementType); + bool CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, + bool topLevel, unsigned& startIndex); + bool CheckForConstantInitializer(Expr *e, QualType t); + + StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType); + bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT); + + // CheckVectorCast - check type constraints for vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size. + // returns true if the cast is invalid + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty); + + // returns true if there were any incompatible arguments. + bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, + ObjCMethodDecl *Method); + + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have + /// the specified width and sign. If an overflow occurs, detect it and emit + /// the specified diagnostic. + void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, unsigned DiagID); + + void InitBuiltinVaListType(); + + //===--------------------------------------------------------------------===// + // Extra semantic analysis beyond the C type system +private: + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); + bool CheckBuiltinCFStringArgument(Expr* Arg); + bool SemaBuiltinVAStart(CallExpr *TheCall); + bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + void CheckPrintfArguments(CallExpr *TheCall, + bool HasVAListArg, unsigned format_idx); + void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc); + void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); +}; + + +} // end namespace clang + +#endif diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp new file mode 100644 index 00000000000..6d3eea5e730 --- /dev/null +++ b/clang/lib/Sema/SemaChecking.cpp @@ -0,0 +1,802 @@ +//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements extra semantic analysis beyond what is enforced +// by the C type system. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "SemaUtil.h" +using namespace clang; + +/// CheckFunctionCall - Check a direct function call for various correctness +/// and safety properties not strictly enforced by the C type system. +bool +Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { + + // Get the IdentifierInfo* for the called function. + IdentifierInfo *FnInfo = FDecl->getIdentifier(); + + switch (FnInfo->getBuiltinID()) { + case Builtin::BI__builtin___CFStringMakeConstantString: + assert(TheCall->getNumArgs() == 1 && + "Wrong # arguments to builtin CFStringMakeConstantString"); + return CheckBuiltinCFStringArgument(TheCall->getArg(0)); + case Builtin::BI__builtin_va_start: + return SemaBuiltinVAStart(TheCall); + + case Builtin::BI__builtin_isgreater: + case Builtin::BI__builtin_isgreaterequal: + case Builtin::BI__builtin_isless: + case Builtin::BI__builtin_islessequal: + case Builtin::BI__builtin_islessgreater: + case Builtin::BI__builtin_isunordered: + return SemaBuiltinUnorderedCompare(TheCall); + } + + // Search the KnownFunctionIDs for the identifier. + unsigned i = 0, e = id_num_known_functions; + for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; } + if (i == e) return false; + + // Printf checking. + if (i <= id_vprintf) { + // Retrieve the index of the format string parameter and determine + // if the function is passed a va_arg argument. + unsigned format_idx = 0; + bool HasVAListArg = false; + + switch (i) { + default: assert(false && "No format string argument index."); + case id_printf: format_idx = 0; break; + case id_fprintf: format_idx = 1; break; + case id_sprintf: format_idx = 1; break; + case id_snprintf: format_idx = 2; break; + case id_asprintf: format_idx = 1; break; + case id_vsnprintf: format_idx = 2; HasVAListArg = true; break; + case id_vasprintf: format_idx = 1; HasVAListArg = true; break; + case id_vfprintf: format_idx = 1; HasVAListArg = true; break; + case id_vsprintf: format_idx = 1; HasVAListArg = true; break; + case id_vprintf: format_idx = 0; HasVAListArg = true; break; + } + + CheckPrintfArguments(TheCall, HasVAListArg, format_idx); + } + + return false; +} + +/// CheckBuiltinCFStringArgument - Checks that the argument to the builtin +/// CFString constructor is correct +bool Sema::CheckBuiltinCFStringArgument(Expr* Arg) { + Arg = Arg->IgnoreParenCasts(); + + StringLiteral *Literal = dyn_cast(Arg); + + if (!Literal || Literal->isWide()) { + Diag(Arg->getLocStart(), + diag::err_cfstring_literal_not_string_constant, + Arg->getSourceRange()); + return true; + } + + const char *Data = Literal->getStrData(); + unsigned Length = Literal->getByteLength(); + + for (unsigned i = 0; i < Length; ++i) { + if (!isascii(Data[i])) { + Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1), + diag::warn_cfstring_literal_contains_non_ascii_character, + Arg->getSourceRange()); + break; + } + + if (!Data[i]) { + Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1), + diag::warn_cfstring_literal_contains_nul_character, + Arg->getSourceRange()); + break; + } + } + + return false; +} + +/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity. +/// Emit an error and return true on failure, return false on success. +bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { + Expr *Fn = TheCall->getCallee(); + if (TheCall->getNumArgs() > 2) { + Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args, Fn->getSourceRange(), + SourceRange(TheCall->getArg(2)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd())); + return true; + } + + // Determine whether the current function is variadic or not. + bool isVariadic; + if (CurFunctionDecl) + isVariadic = + cast(CurFunctionDecl->getType())->isVariadic(); + else + isVariadic = CurMethodDecl->isVariadic(); + + if (!isVariadic) { + Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); + return true; + } + + // Verify that the second argument to the builtin is the last argument of the + // current function or method. + bool SecondArgIsLastNamedArgument = false; + const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); + + if (const DeclRefExpr *DR = dyn_cast(Arg)) { + if (const ParmVarDecl *PV = dyn_cast(DR->getDecl())) { + // FIXME: This isn't correct for methods (results in bogus warning). + // Get the last formal in the current function. + const ParmVarDecl *LastArg; + if (CurFunctionDecl) + LastArg = *(CurFunctionDecl->param_end()-1); + else + LastArg = *(CurMethodDecl->param_end()-1); + SecondArgIsLastNamedArgument = PV == LastArg; + } + } + + if (!SecondArgIsLastNamedArgument) + Diag(TheCall->getArg(1)->getLocStart(), + diag::warn_second_parameter_of_va_start_not_last_named_argument); + return false; +} + +/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and +/// friends. This is declared to take (...), so we have to check everything. +bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { + if (TheCall->getNumArgs() < 2) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args); + if (TheCall->getNumArgs() > 2) + return Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args, + SourceRange(TheCall->getArg(2)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd())); + + Expr *OrigArg0 = TheCall->getArg(0); + Expr *OrigArg1 = TheCall->getArg(1); + + // Do standard promotions between the two arguments, returning their common + // type. + QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); + + // If the common type isn't a real floating type, then the arguments were + // invalid for this operation. + if (!Res->isRealFloatingType()) + return Diag(OrigArg0->getLocStart(), + diag::err_typecheck_call_invalid_ordered_compare, + OrigArg0->getType().getAsString(), + OrigArg1->getType().getAsString(), + SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd())); + + return false; +} + + +/// CheckPrintfArguments - Check calls to printf (and similar functions) for +/// correct use of format strings. +/// +/// HasVAListArg - A predicate indicating whether the printf-like +/// function is passed an explicit va_arg argument (e.g., vprintf) +/// +/// format_idx - The index into Args for the format string. +/// +/// Improper format strings to functions in the printf family can be +/// the source of bizarre bugs and very serious security holes. A +/// good source of information is available in the following paper +/// (which includes additional references): +/// +/// FormatGuard: Automatic Protection From printf Format String +/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001. +/// +/// Functionality implemented: +/// +/// We can statically check the following properties for string +/// literal format strings for non v.*printf functions (where the +/// arguments are passed directly): +// +/// (1) Are the number of format conversions equal to the number of +/// data arguments? +/// +/// (2) Does each format conversion correctly match the type of the +/// corresponding data argument? (TODO) +/// +/// Moreover, for all printf functions we can: +/// +/// (3) Check for a missing format string (when not caught by type checking). +/// +/// (4) Check for no-operation flags; e.g. using "#" with format +/// conversion 'c' (TODO) +/// +/// (5) Check the use of '%n', a major source of security holes. +/// +/// (6) Check for malformed format conversions that don't specify anything. +/// +/// (7) Check for empty format strings. e.g: printf(""); +/// +/// (8) Check that the format string is a wide literal. +/// +/// (9) Also check the arguments of functions with the __format__ attribute. +/// (TODO). +/// +/// All of these checks can be done by parsing the format string. +/// +/// For now, we ONLY do (1), (3), (5), (6), (7), and (8). +void +Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx) { + Expr *Fn = TheCall->getCallee(); + + // CHECK: printf-like function is called with no format string. + if (format_idx >= TheCall->getNumArgs()) { + Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string, + Fn->getSourceRange()); + return; + } + + Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts(); + + // CHECK: format string is not a string literal. + // + // Dynamically generated format strings are difficult to + // automatically vet at compile time. Requiring that format strings + // are string literals: (1) permits the checking of format strings by + // the compiler and thereby (2) can practically remove the source of + // many format string exploits. + StringLiteral *FExpr = dyn_cast(OrigFormatExpr); + if (FExpr == NULL) { + // For vprintf* functions (i.e., HasVAListArg==true), we add a + // special check to see if the format string is a function parameter + // of the function calling the printf function. If the function + // has an attribute indicating it is a printf-like function, then we + // should suppress warnings concerning non-literals being used in a call + // to a vprintf function. For example: + // + // void + // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...) { + // va_list ap; + // va_start(ap, fmt); + // vprintf(fmt, ap); // Do NOT emit a warning about "fmt". + // ... + // + // + // FIXME: We don't have full attribute support yet, so just check to see + // if the argument is a DeclRefExpr that references a parameter. We'll + // add proper support for checking the attribute later. + if (HasVAListArg) + if (DeclRefExpr* DR = dyn_cast(OrigFormatExpr)) + if (isa(DR->getDecl())) + return; + + Diag(TheCall->getArg(format_idx)->getLocStart(), + diag::warn_printf_not_string_constant, Fn->getSourceRange()); + return; + } + + // CHECK: is the format string a wide literal? + if (FExpr->isWide()) { + Diag(FExpr->getLocStart(), + diag::warn_printf_format_string_is_wide_literal, Fn->getSourceRange()); + return; + } + + // Str - The format string. NOTE: this is NOT null-terminated! + const char * const Str = FExpr->getStrData(); + + // CHECK: empty format string? + const unsigned StrLen = FExpr->getByteLength(); + + if (StrLen == 0) { + Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string, + Fn->getSourceRange()); + return; + } + + // We process the format string using a binary state machine. The + // current state is stored in CurrentState. + enum { + state_OrdChr, + state_Conversion + } CurrentState = state_OrdChr; + + // numConversions - The number of conversions seen so far. This is + // incremented as we traverse the format string. + unsigned numConversions = 0; + + // numDataArgs - The number of data arguments after the format + // string. This can only be determined for non vprintf-like + // functions. For those functions, this value is 1 (the sole + // va_arg argument). + unsigned numDataArgs = TheCall->getNumArgs()-(format_idx+1); + + // Inspect the format string. + unsigned StrIdx = 0; + + // LastConversionIdx - Index within the format string where we last saw + // a '%' character that starts a new format conversion. + unsigned LastConversionIdx = 0; + + for (; StrIdx < StrLen; ++StrIdx) { + + // Is the number of detected conversion conversions greater than + // the number of matching data arguments? If so, stop. + if (!HasVAListArg && numConversions > numDataArgs) break; + + // Handle "\0" + if (Str[StrIdx] == '\0') { + // The string returned by getStrData() is not null-terminated, + // so the presence of a null character is likely an error. + Diag(PP.AdvanceToTokenCharacter(FExpr->getLocStart(), StrIdx+1), + diag::warn_printf_format_string_contains_null_char, + Fn->getSourceRange()); + return; + } + + // Ordinary characters (not processing a format conversion). + if (CurrentState == state_OrdChr) { + if (Str[StrIdx] == '%') { + CurrentState = state_Conversion; + LastConversionIdx = StrIdx; + } + continue; + } + + // Seen '%'. Now processing a format conversion. + switch (Str[StrIdx]) { + // Handle dynamic precision or width specifier. + case '*': { + ++numConversions; + + if (!HasVAListArg && numConversions > numDataArgs) { + SourceLocation Loc = FExpr->getLocStart(); + Loc = PP.AdvanceToTokenCharacter(Loc, StrIdx+1); + + if (Str[StrIdx-1] == '.') + Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg, + Fn->getSourceRange()); + else + Diag(Loc, diag::warn_printf_asterisk_width_missing_arg, + Fn->getSourceRange()); + + // Don't do any more checking. We'll just emit spurious errors. + return; + } + + // Perform type checking on width/precision specifier. + Expr *E = TheCall->getArg(format_idx+numConversions); + if (const BuiltinType *BT = E->getType()->getAsBuiltinType()) + if (BT->getKind() == BuiltinType::Int) + break; + + SourceLocation Loc = + PP.AdvanceToTokenCharacter(FExpr->getLocStart(), StrIdx+1); + + if (Str[StrIdx-1] == '.') + Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type, + E->getType().getAsString(), E->getSourceRange()); + else + Diag(Loc, diag::warn_printf_asterisk_width_wrong_type, + E->getType().getAsString(), E->getSourceRange()); + + break; + } + + // Characters which can terminate a format conversion + // (e.g. "%d"). Characters that specify length modifiers or + // other flags are handled by the default case below. + // + // FIXME: additional checks will go into the following cases. + case 'i': + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + case 'D': + case 'O': + case 'U': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + case 'c': + case 'C': + case 'S': + case 's': + case 'p': + ++numConversions; + CurrentState = state_OrdChr; + break; + + // CHECK: Are we using "%n"? Issue a warning. + case 'n': { + ++numConversions; + CurrentState = state_OrdChr; + SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), + LastConversionIdx+1); + + Diag(Loc, diag::warn_printf_write_back, Fn->getSourceRange()); + break; + } + + // Handle "%%" + case '%': + // Sanity check: Was the first "%" character the previous one? + // If not, we will assume that we have a malformed format + // conversion, and that the current "%" character is the start + // of a new conversion. + if (StrIdx - LastConversionIdx == 1) + CurrentState = state_OrdChr; + else { + // Issue a warning: invalid format conversion. + SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), + LastConversionIdx+1); + + Diag(Loc, diag::warn_printf_invalid_conversion, + std::string(Str+LastConversionIdx, Str+StrIdx), + Fn->getSourceRange()); + + // This conversion is broken. Advance to the next format + // conversion. + LastConversionIdx = StrIdx; + ++numConversions; + } + break; + + default: + // This case catches all other characters: flags, widths, etc. + // We should eventually process those as well. + break; + } + } + + if (CurrentState == state_Conversion) { + // Issue a warning: invalid format conversion. + SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), + LastConversionIdx+1); + + Diag(Loc, diag::warn_printf_invalid_conversion, + std::string(Str+LastConversionIdx, + Str+std::min(LastConversionIdx+2, StrLen)), + Fn->getSourceRange()); + return; + } + + if (!HasVAListArg) { + // CHECK: Does the number of format conversions exceed the number + // of data arguments? + if (numConversions > numDataArgs) { + SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(), + LastConversionIdx); + + Diag(Loc, diag::warn_printf_insufficient_data_args, + Fn->getSourceRange()); + } + // CHECK: Does the number of data arguments exceed the number of + // format conversions in the format string? + else if (numConversions < numDataArgs) + Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(), + diag::warn_printf_too_many_data_args, Fn->getSourceRange()); + } +} + +//===--- CHECK: Return Address of Stack Variable --------------------------===// + +static DeclRefExpr* EvalVal(Expr *E); +static DeclRefExpr* EvalAddr(Expr* E); + +/// CheckReturnStackAddr - Check if a return statement returns the address +/// of a stack variable. +void +Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc) { + + // Perform checking for returned stack addresses. + if (lhsType->isPointerType()) { + if (DeclRefExpr *DR = EvalAddr(RetValExp)) + Diag(DR->getLocStart(), diag::warn_ret_stack_addr, + DR->getDecl()->getIdentifier()->getName(), + RetValExp->getSourceRange()); + } + // Perform checking for stack values returned by reference. + else if (lhsType->isReferenceType()) { + // Check for an implicit cast to a reference. + if (ImplicitCastExpr *I = dyn_cast(RetValExp)) + if (DeclRefExpr *DR = EvalVal(I->getSubExpr())) + Diag(DR->getLocStart(), diag::warn_ret_stack_ref, + DR->getDecl()->getIdentifier()->getName(), + RetValExp->getSourceRange()); + } +} + +/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that +/// check if the expression in a return statement evaluates to an address +/// to a location on the stack. The recursion is used to traverse the +/// AST of the return expression, with recursion backtracking when we +/// encounter a subexpression that (1) clearly does not lead to the address +/// of a stack variable or (2) is something we cannot determine leads to +/// the address of a stack variable based on such local checking. +/// +/// EvalAddr processes expressions that are pointers that are used as +/// references (and not L-values). EvalVal handles all other values. +/// At the base case of the recursion is a check for a DeclRefExpr* in +/// the refers to a stack variable. +/// +/// This implementation handles: +/// +/// * pointer-to-pointer casts +/// * implicit conversions from array references to pointers +/// * taking the address of fields +/// * arbitrary interplay between "&" and "*" operators +/// * pointer arithmetic from an address of a stack variable +/// * taking the address of an array element where the array is on the stack +static DeclRefExpr* EvalAddr(Expr *E) { + // We should only be called for evaluating pointer expressions. + assert((E->getType()->isPointerType() || + E->getType()->isObjCQualifiedIdType()) && + "EvalAddr only works on pointers"); + + // Our "symbolic interpreter" is just a dispatch off the currently + // viewed AST node. We then recursively traverse the AST by calling + // EvalAddr and EvalVal appropriately. + switch (E->getStmtClass()) { + case Stmt::ParenExprClass: + // Ignore parentheses. + return EvalAddr(cast(E)->getSubExpr()); + + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is AddrOf. All others don't make sense as pointers. + UnaryOperator *U = cast(E); + + if (U->getOpcode() == UnaryOperator::AddrOf) + return EvalVal(U->getSubExpr()); + else + return NULL; + } + + case Stmt::BinaryOperatorClass: { + // Handle pointer arithmetic. All other binary operators are not valid + // in this context. + BinaryOperator *B = cast(E); + BinaryOperator::Opcode op = B->getOpcode(); + + if (op != BinaryOperator::Add && op != BinaryOperator::Sub) + return NULL; + + Expr *Base = B->getLHS(); + + // Determine which argument is the real pointer base. It could be + // the RHS argument instead of the LHS. + if (!Base->getType()->isPointerType()) Base = B->getRHS(); + + assert (Base->getType()->isPointerType()); + return EvalAddr(Base); + } + + // For conditional operators we need to see if either the LHS or RHS are + // valid DeclRefExpr*s. If one of them is valid, we return it. + case Stmt::ConditionalOperatorClass: { + ConditionalOperator *C = cast(E); + + // Handle the GNU extension for missing LHS. + if (Expr *lhsExpr = C->getLHS()) + if (DeclRefExpr* LHS = EvalAddr(lhsExpr)) + return LHS; + + return EvalAddr(C->getRHS()); + } + + // For implicit casts, we need to handle conversions from arrays to + // pointer values, and implicit pointer-to-pointer conversions. + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr *IE = cast(E); + Expr* SubExpr = IE->getSubExpr(); + + if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isObjCQualifiedIdType()) + return EvalAddr(SubExpr); + else + return EvalVal(SubExpr); + } + + // For casts, we handle pointer-to-pointer conversions (which + // is essentially a no-op from our mini-interpreter's standpoint). + // For other casts we abort. + case Stmt::CastExprClass: { + CastExpr *C = cast(E); + Expr *SubExpr = C->getSubExpr(); + + if (SubExpr->getType()->isPointerType()) + return EvalAddr(SubExpr); + else + return NULL; + } + + // C++ casts. For dynamic casts, static casts, and const casts, we + // are always converting from a pointer-to-pointer, so we just blow + // through the cast. In the case the dynamic cast doesn't fail + // (and return NULL), we take the conservative route and report cases + // where we return the address of a stack variable. For Reinterpre + case Stmt::CXXCastExprClass: { + CXXCastExpr *C = cast(E); + + if (C->getOpcode() == CXXCastExpr::ReinterpretCast) { + Expr *S = C->getSubExpr(); + if (S->getType()->isPointerType()) + return EvalAddr(S); + else + return NULL; + } + else + return EvalAddr(C->getSubExpr()); + } + + // Everything else: we simply don't reason about them. + default: + return NULL; + } +} + + +/// EvalVal - This function is complements EvalAddr in the mutual recursion. +/// See the comments for EvalAddr for more details. +static DeclRefExpr* EvalVal(Expr *E) { + + // We should only be called for evaluating non-pointer expressions, or + // expressions with a pointer type that are not used as references but instead + // are l-values (e.g., DeclRefExpr with a pointer type). + + // Our "symbolic interpreter" is just a dispatch off the currently + // viewed AST node. We then recursively traverse the AST by calling + // EvalAddr and EvalVal appropriately. + switch (E->getStmtClass()) { + case Stmt::DeclRefExprClass: { + // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking + // at code that refers to a variable's name. We check if it has local + // storage within the function, and if so, return the expression. + DeclRefExpr *DR = cast(E); + + if (VarDecl *V = dyn_cast(DR->getDecl())) + if(V->hasLocalStorage()) return DR; + + return NULL; + } + + case Stmt::ParenExprClass: + // Ignore parentheses. + return EvalVal(cast(E)->getSubExpr()); + + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is Deref. All others don't resolve to a "name." This includes + // handling all sorts of rvalues passed to a unary operator. + UnaryOperator *U = cast(E); + + if (U->getOpcode() == UnaryOperator::Deref) + return EvalAddr(U->getSubExpr()); + + return NULL; + } + + case Stmt::ArraySubscriptExprClass: { + // Array subscripts are potential references to data on the stack. We + // retrieve the DeclRefExpr* for the array variable if it indeed + // has local storage. + return EvalAddr(cast(E)->getBase()); + } + + case Stmt::ConditionalOperatorClass: { + // For conditional operators we need to see if either the LHS or RHS are + // non-NULL DeclRefExpr's. If one is non-NULL, we return it. + ConditionalOperator *C = cast(E); + + // Handle the GNU extension for missing LHS. + if (Expr *lhsExpr = C->getLHS()) + if (DeclRefExpr *LHS = EvalVal(lhsExpr)) + return LHS; + + return EvalVal(C->getRHS()); + } + + // Accesses to members are potential references to data on the stack. + case Stmt::MemberExprClass: { + MemberExpr *M = cast(E); + + // Check for indirect access. We only want direct field accesses. + if (!M->isArrow()) + return EvalVal(M->getBase()); + else + return NULL; + } + + // Everything else: we simply don't reason about them. + default: + return NULL; + } +} + +//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// + +/// Check for comparisons of floating point operands using != and ==. +/// Issue a warning if these are no self-comparisons, as they are not likely +/// to do what the programmer intended. +void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { + bool EmitWarning = true; + + Expr* LeftExprSansParen = lex->IgnoreParens(); + Expr* RightExprSansParen = rex->IgnoreParens(); + + // Special case: check for x == x (which is OK). + // Do not emit warnings for such cases. + if (DeclRefExpr* DRL = dyn_cast(LeftExprSansParen)) + if (DeclRefExpr* DRR = dyn_cast(RightExprSansParen)) + if (DRL->getDecl() == DRR->getDecl()) + EmitWarning = false; + + + // Special case: check for comparisons against literals that can be exactly + // represented by APFloat. In such cases, do not emit a warning. This + // is a heuristic: often comparison against such literals are used to + // detect if a value in a variable has not changed. This clearly can + // lead to false negatives. + if (EmitWarning) { + if (FloatingLiteral* FLL = dyn_cast(LeftExprSansParen)) { + if (FLL->isExact()) + EmitWarning = false; + } + else + if (FloatingLiteral* FLR = dyn_cast(RightExprSansParen)){ + if (FLR->isExact()) + EmitWarning = false; + } + } + + // Check for comparisons with builtin types. + if (EmitWarning) + if (CallExpr* CL = dyn_cast(LeftExprSansParen)) + if (isCallBuiltin(CL)) + EmitWarning = false; + + if (EmitWarning) + if (CallExpr* CR = dyn_cast(RightExprSansParen)) + if (isCallBuiltin(CR)) + EmitWarning = false; + + // Emit the diagnostic. + if (EmitWarning) + Diag(loc, diag::warn_floatingpoint_eq, + lex->getSourceRange(),rex->getSourceRange()); +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp new file mode 100644 index 00000000000..7914e865741 --- /dev/null +++ b/clang/lib/Sema/SemaDecl.cpp @@ -0,0 +1,2297 @@ +//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Builtins.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/SourceManager.h" +// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/DenseSet.h" +using namespace clang; + +Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const { + Decl *IIDecl = II.getFETokenInfo(); + // Find first occurance of none-tagged declaration + while(IIDecl && IIDecl->getIdentifierNamespace() != Decl::IDNS_Ordinary) + IIDecl = cast(IIDecl)->getNext(); + if (!IIDecl) + return 0; + if (isa(IIDecl) || isa(IIDecl)) + return IIDecl; + if (ObjCCompatibleAliasDecl *ADecl = + dyn_cast(IIDecl)) + return ADecl->getClassInterface(); + return 0; +} + +void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { + if (S->decl_empty()) return; + assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!"); + + for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); + I != E; ++I) { + Decl *TmpD = static_cast(*I); + assert(TmpD && "This decl didn't get pushed??"); + ScopedDecl *D = dyn_cast(TmpD); + assert(D && "This decl isn't a ScopedDecl?"); + + IdentifierInfo *II = D->getIdentifier(); + if (!II) continue; + + // Unlink this decl from the identifier. Because the scope contains decls + // in an unordered collection, and because we have multiple identifier + // namespaces (e.g. tag, normal, label),the decl may not be the first entry. + if (II->getFETokenInfo() == D) { + // Normal case, no multiple decls in different namespaces. + II->setFETokenInfo(D->getNext()); + } else { + // Scan ahead. There are only three namespaces in C, so this loop can + // never execute more than 3 times. + ScopedDecl *SomeDecl = II->getFETokenInfo(); + while (SomeDecl->getNext() != D) { + SomeDecl = SomeDecl->getNext(); + assert(SomeDecl && "Didn't find this decl on its identifier's chain!"); + } + SomeDecl->setNext(D->getNext()); + } + + // This will have to be revisited for C++: there we want to nest stuff in + // namespace decls etc. Even for C, we might want a top-level translation + // unit decl or something. + if (!CurFunctionDecl) + continue; + + // Chain this decl to the containing function, it now owns the memory for + // the decl. + D->setNext(CurFunctionDecl->getDeclChain()); + CurFunctionDecl->setDeclChain(D); + } +} + +/// LookupInterfaceDecl - Lookup interface declaration in the scope chain. +/// Return the first declaration found (which may or may not be a class +/// declaration. Caller is responsible for handling the none-class case. +/// Bypassing the alias of a class by returning the aliased class. +ScopedDecl *Sema::LookupInterfaceDecl(IdentifierInfo *ClassName) { + ScopedDecl *IDecl; + // Scan up the scope chain looking for a decl that matches this identifier + // that is in the appropriate namespace. + for (IDecl = ClassName->getFETokenInfo(); IDecl; + IDecl = IDecl->getNext()) + if (IDecl->getIdentifierNamespace() == Decl::IDNS_Ordinary) + break; + + if (ObjCCompatibleAliasDecl *ADecl = + dyn_cast_or_null(IDecl)) + return ADecl->getClassInterface(); + return IDecl; +} + +/// getObjCInterfaceDecl - Look up a for a class declaration in the scope. +/// return 0 if one not found. +ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { + ScopedDecl *IdDecl = LookupInterfaceDecl(Id); + return cast_or_null(IdDecl); +} + +/// LookupScopedDecl - Look up the inner-most declaration in the specified +/// namespace. +ScopedDecl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI, + SourceLocation IdLoc, Scope *S) { + if (II == 0) return 0; + Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI; + + // Scan up the scope chain looking for a decl that matches this identifier + // that is in the appropriate namespace. This search should not take long, as + // shadowing of names is uncommon, and deep shadowing is extremely uncommon. + for (ScopedDecl *D = II->getFETokenInfo(); D; D = D->getNext()) + if (D->getIdentifierNamespace() == NS) + return D; + + // If we didn't find a use of this identifier, and if the identifier + // corresponds to a compiler builtin, create the decl object for the builtin + // now, injecting it into translation unit scope, and return it. + if (NS == Decl::IDNS_Ordinary) { + // If this is a builtin on this (or all) targets, create the decl. + if (unsigned BuiltinID = II->getBuiltinID()) + return LazilyCreateBuiltin(II, BuiltinID, S); + } + return 0; +} + +void Sema::InitBuiltinVaListType() +{ + if (!Context.getBuiltinVaListType().isNull()) + return; + + IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); + ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary, + SourceLocation(), TUScope); + TypedefDecl *VaTypedef = cast(VaDecl); + Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); +} + +/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope. +/// lazily create a decl for it. +ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, + Scope *S) { + Builtin::ID BID = (Builtin::ID)bid; + + if (BID == Builtin::BI__builtin_va_start || + BID == Builtin::BI__builtin_va_copy || + BID == Builtin::BI__builtin_va_end) + InitBuiltinVaListType(); + + QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context); + FunctionDecl *New = FunctionDecl::Create(Context, SourceLocation(), II, R, + FunctionDecl::Extern, false, 0); + + // Find translation-unit scope to insert this function into. + if (Scope *FnS = S->getFnParent()) + S = FnS->getParent(); // Skip all scopes in a function at once. + while (S->getParent()) + S = S->getParent(); + S->AddDecl(New); + + // Add this decl to the end of the identifier info. + if (ScopedDecl *LastDecl = II->getFETokenInfo()) { + // Scan until we find the last (outermost) decl in the id chain. + while (LastDecl->getNext()) + LastDecl = LastDecl->getNext(); + // Insert before (outside) it. + LastDecl->setNext(New); + } else { + II->setFETokenInfo(New); + } + return New; +} + +/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the same name +/// and scope as a previous declaration 'Old'. Figure out how to resolve this +/// situation, merging decls or emitting diagnostics as appropriate. +/// +TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) { + // Verify the old decl was also a typedef. + TypedefDecl *Old = dyn_cast(OldD); + if (!Old) { + Diag(New->getLocation(), diag::err_redefinition_different_kind, + New->getName()); + Diag(OldD->getLocation(), diag::err_previous_definition); + return New; + } + + // Allow multiple definitions for ObjC built-in typedefs. + // FIXME: Verify the underlying types are equivalent! + if (getLangOptions().ObjC1 && isBuiltinObjCType(New)) + return Old; + + // Redeclaration of a type is a constraint violation (6.7.2.3p1). + // Apparently GCC, Intel, and Sun all silently ignore the redeclaration if + // *either* declaration is in a system header. The code below implements + // this adhoc compatibility rule. FIXME: The following code will not + // work properly when compiling ".i" files (containing preprocessed output). + SourceManager &SrcMgr = Context.getSourceManager(); + const FileEntry *OldDeclFile = SrcMgr.getFileEntryForLoc(Old->getLocation()); + const FileEntry *NewDeclFile = SrcMgr.getFileEntryForLoc(New->getLocation()); + HeaderSearch &HdrInfo = PP.getHeaderSearchInfo(); + DirectoryLookup::DirType OldDirType = HdrInfo.getFileDirFlavor(OldDeclFile); + DirectoryLookup::DirType NewDirType = HdrInfo.getFileDirFlavor(NewDeclFile); + + if ((OldDirType == DirectoryLookup::ExternCSystemHeaderDir || + NewDirType == DirectoryLookup::ExternCSystemHeaderDir) || + getLangOptions().Microsoft) + return New; + + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. + // TODO: This is totally simplistic. It should handle merging functions + // together etc, merging extern int X; int X; ... + Diag(New->getLocation(), diag::err_redefinition, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; +} + +/// DeclhasAttr - returns true if decl Declaration already has the target attribute. +static bool DeclHasAttr(const Decl *decl, const Attr *target) { + for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext()) + if (attr->getKind() == target->getKind()) + return true; + + return false; +} + +/// MergeAttributes - append attributes from the Old decl to the New one. +static void MergeAttributes(Decl *New, Decl *Old) { + Attr *attr = const_cast(Old->getAttrs()), *tmp; + +// FIXME: fix this code to cleanup the Old attrs correctly + while (attr) { + tmp = attr; + attr = attr->getNext(); + + if (!DeclHasAttr(New, tmp)) { + New->addAttr(tmp); + } else { + tmp->setNext(0); + delete(tmp); + } + } +} + +/// MergeFunctionDecl - We just parsed a function 'New' which has the same name +/// and scope as a previous declaration 'Old'. Figure out how to resolve this +/// situation, merging decls or emitting diagnostics as appropriate. +/// +FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, ScopedDecl *OldD) { + // Verify the old decl was also a function. + FunctionDecl *Old = dyn_cast(OldD); + if (!Old) { + Diag(New->getLocation(), diag::err_redefinition_different_kind, + New->getName()); + Diag(OldD->getLocation(), diag::err_previous_definition); + return New; + } + + MergeAttributes(New, Old); + + + QualType OldQType = Old->getCanonicalType(); + QualType NewQType = New->getCanonicalType(); + + // Function types need to be compatible, not identical. This handles + // duplicate function decls like "void f(int); void f(enum X);" properly. + if (Context.functionTypesAreCompatible(OldQType, NewQType)) + return New; + + // A function that has already been declared has been redeclared or defined + // with a different type- show appropriate diagnostic + diag::kind PrevDiag = Old->getBody() ? diag::err_previous_definition : + diag::err_previous_declaration; + + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. + // TODO: This is totally simplistic. It should handle merging functions + // together etc, merging extern int X; int X; ... + Diag(New->getLocation(), diag::err_conflicting_types, New->getName()); + Diag(Old->getLocation(), PrevDiag); + return New; +} + +/// equivalentArrayTypes - Used to determine whether two array types are +/// equivalent. +/// We need to check this explicitly as an incomplete array definition is +/// considered a VariableArrayType, so will not match a complete array +/// definition that would be otherwise equivalent. +static bool areEquivalentArrayTypes(QualType NewQType, QualType OldQType) { + const ArrayType *NewAT = NewQType->getAsArrayType(); + const ArrayType *OldAT = OldQType->getAsArrayType(); + + if (!NewAT || !OldAT) + return false; + + // If either (or both) array types in incomplete we need to strip off the + // outer VariableArrayType. Once the outer VAT is removed the remaining + // types must be identical if the array types are to be considered + // equivalent. + // eg. int[][1] and int[1][1] become + // VAT(null, CAT(1, int)) and CAT(1, CAT(1, int)) + // removing the outermost VAT gives + // CAT(1, int) and CAT(1, int) + // which are equal, therefore the array types are equivalent. + if (NewAT->isIncompleteArrayType() || OldAT->isIncompleteArrayType()) { + if (NewAT->getIndexTypeQualifier() != OldAT->getIndexTypeQualifier()) + return false; + NewQType = NewAT->getElementType().getCanonicalType(); + OldQType = OldAT->getElementType().getCanonicalType(); + } + + return NewQType == OldQType; +} + +/// MergeVarDecl - We just parsed a variable 'New' which has the same name +/// and scope as a previous declaration 'Old'. Figure out how to resolve this +/// situation, merging decls or emitting diagnostics as appropriate. +/// +/// FIXME: Need to carefully consider tentative definition rules (C99 6.9.2p2). +/// For example, we incorrectly complain about i1, i4 from C99 6.9.2p4. +/// +VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) { + // Verify the old decl was also a variable. + VarDecl *Old = dyn_cast(OldD); + if (!Old) { + Diag(New->getLocation(), diag::err_redefinition_different_kind, + New->getName()); + Diag(OldD->getLocation(), diag::err_previous_definition); + return New; + } + + MergeAttributes(New, Old); + + // Verify the types match. + if (Old->getCanonicalType() != New->getCanonicalType() && + !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) { + Diag(New->getLocation(), diag::err_redefinition, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; + } + // C99 6.2.2p4: Check if we have a static decl followed by a non-static. + if (New->getStorageClass() == VarDecl::Static && + (Old->getStorageClass() == VarDecl::None || + Old->getStorageClass() == VarDecl::Extern)) { + Diag(New->getLocation(), diag::err_static_non_static, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; + } + // C99 6.2.2p4: Check if we have a non-static decl followed by a static. + if (New->getStorageClass() != VarDecl::Static && + Old->getStorageClass() == VarDecl::Static) { + Diag(New->getLocation(), diag::err_non_static_static, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + return New; + } + // We've verified the types match, now handle "tentative" definitions. + FileVarDecl *OldFSDecl = dyn_cast(Old); + FileVarDecl *NewFSDecl = dyn_cast(New); + + if (OldFSDecl && NewFSDecl) { + // Handle C "tentative" external object definitions (C99 6.9.2). + bool OldIsTentative = false; + bool NewIsTentative = false; + + if (!OldFSDecl->getInit() && + (OldFSDecl->getStorageClass() == VarDecl::None || + OldFSDecl->getStorageClass() == VarDecl::Static)) + OldIsTentative = true; + + // FIXME: this check doesn't work (since the initializer hasn't been + // attached yet). This check should be moved to FinalizeDeclaratorGroup. + // Unfortunately, by the time we get to FinializeDeclaratorGroup, we've + // thrown out the old decl. + if (!NewFSDecl->getInit() && + (NewFSDecl->getStorageClass() == VarDecl::None || + NewFSDecl->getStorageClass() == VarDecl::Static)) + ; // change to NewIsTentative = true; once the code is moved. + + if (NewIsTentative || OldIsTentative) + return New; + } + if (Old->getStorageClass() != VarDecl::Extern && + New->getStorageClass() != VarDecl::Extern) { + Diag(New->getLocation(), diag::err_redefinition, New->getName()); + Diag(Old->getLocation(), diag::err_previous_definition); + } + return New; +} + +/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with +/// no declarator (e.g. "struct foo;") is parsed. +Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + // TODO: emit error on 'int;' or 'const enum foo;'. + // TODO: emit error on 'typedef int;' + // if (!DS.isMissingDeclaratorOk()) Diag(...); + + return dyn_cast_or_null(static_cast(DS.getTypeRep())); +} + +bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) { + // Get the type before calling CheckSingleAssignmentConstraints(), since + // it can promote the expression. + QualType InitType = Init->getType(); + + AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init); + return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, + InitType, Init, "initializing"); +} + +bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, + QualType ElementType) { + Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. + if (CheckSingleInitializer(expr, ElementType)) + return true; // types weren't compatible. + + if (savExpr != expr) // The type was promoted, update initializer list. + IList->setInit(slot, expr); + return false; +} + +bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { + if (const IncompleteArrayType *IAT = DeclT->getAsIncompleteArrayType()) { + // C99 6.7.8p14. We have an array of character type with unknown size + // being initialized to a string literal. + llvm::APSInt ConstVal(32); + ConstVal = strLiteral->getByteLength() + 1; + // Return a new array type (C99 6.7.8p22). + DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal, + ArrayType::Normal, 0); + } else if (const ConstantArrayType *CAT = DeclT->getAsConstantArrayType()) { + // C99 6.7.8p14. We have an array of character type with known size. + if (strLiteral->getByteLength() > (unsigned)CAT->getMaximumElements()) + Diag(strLiteral->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long, + strLiteral->getSourceRange()); + } else { + assert(0 && "HandleStringLiteralInit(): Invalid array type"); + } + // Set type from "char *" to "constant array of char". + strLiteral->setType(DeclT); + // For now, we always return false (meaning success). + return false; +} + +StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) { + const ArrayType *AT = DeclType->getAsArrayType(); + if (AT && AT->getElementType()->isCharType()) { + return dyn_cast(Init); + } + return 0; +} + +// CheckInitializerListTypes - Checks the types of elements of an initializer +// list. This function is recursive: it calls itself to initialize subelements +// of aggregate types. Note that the topLevel parameter essentially refers to +// whether this expression "owns" the initializer list passed in, or if this +// initialization is taking elements out of a parent initializer. Each +// call to this function adds zero or more to startIndex, reports any errors, +// and returns true if it found any inconsistent types. +bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, + bool topLevel, unsigned& startIndex) { + bool hadError = false; + + if (DeclType->isScalarType()) { + // The simplest case: initializing a single scalar + if (topLevel) { + Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init, + IList->getSourceRange()); + } + if (startIndex < IList->getNumInits()) { + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + // FIXME: Should an error be reported here instead? + unsigned newIndex = 0; + CheckInitializerListTypes(SubInitList, DeclType, true, newIndex); + } else { + hadError |= CheckInitExpr(expr, IList, startIndex, DeclType); + } + ++startIndex; + } + // FIXME: Should an error be reported for empty initializer list + scalar? + } else if (DeclType->isVectorType()) { + if (startIndex < IList->getNumInits()) { + const VectorType *VT = DeclType->getAsVectorType(); + int maxElements = VT->getNumElements(); + QualType elementType = VT->getElementType(); + + for (int i = 0; i < maxElements; ++i) { + // Don't attempt to go past the end of the init list + if (startIndex >= IList->getNumInits()) + break; + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + unsigned newIndex = 0; + hadError |= CheckInitializerListTypes(SubInitList, elementType, + true, newIndex); + ++startIndex; + } else { + hadError |= CheckInitializerListTypes(IList, elementType, + false, startIndex); + } + } + } + } else if (DeclType->isAggregateType() || DeclType->isUnionType()) { + if (DeclType->isStructureType() || DeclType->isUnionType()) { + if (startIndex < IList->getNumInits() && !topLevel && + Context.typesAreCompatible(IList->getInit(startIndex)->getType(), + DeclType)) { + // We found a compatible struct; per the standard, this initializes the + // struct. (The C standard technically says that this only applies for + // initializers for declarations with automatic scope; however, this + // construct is unambiguous anyway because a struct cannot contain + // a type compatible with itself. We'll output an error when we check + // if the initializer is constant.) + // FIXME: Is a call to CheckSingleInitializer required here? + ++startIndex; + } else { + RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); + + // If the record is invalid, some of it's members are invalid. To avoid + // confusion, we forgo checking the intializer for the entire record. + if (structDecl->isInvalidDecl()) + return true; + + // If structDecl is a forward declaration, this loop won't do anything; + // That's okay, because an error should get printed out elsewhere. It + // might be worthwhile to skip over the rest of the initializer, though. + int numMembers = structDecl->getNumMembers() - + structDecl->hasFlexibleArrayMember(); + for (int i = 0; i < numMembers; i++) { + // Don't attempt to go past the end of the init list + if (startIndex >= IList->getNumInits()) + break; + FieldDecl * curField = structDecl->getMember(i); + if (!curField->getIdentifier()) { + // Don't initialize unnamed fields, e.g. "int : 20;" + continue; + } + QualType fieldType = curField->getType(); + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + unsigned newStart = 0; + hadError |= CheckInitializerListTypes(SubInitList, fieldType, + true, newStart); + ++startIndex; + } else { + hadError |= CheckInitializerListTypes(IList, fieldType, + false, startIndex); + } + if (DeclType->isUnionType()) + break; + } + // FIXME: Implement flexible array initialization GCC extension (it's a + // really messy extension to implement, unfortunately...the necessary + // information isn't actually even here!) + } + } else if (DeclType->isArrayType()) { + // Check for the special-case of initializing an array with a string. + if (startIndex < IList->getNumInits()) { + if (StringLiteral *lit = IsStringLiteralInit(IList->getInit(startIndex), + DeclType)) { + CheckStringLiteralInit(lit, DeclType); + ++startIndex; + if (topLevel && startIndex < IList->getNumInits()) { + // We have leftover initializers; warn + Diag(IList->getInit(startIndex)->getLocStart(), + diag::err_excess_initializers_in_char_array_initializer, + IList->getInit(startIndex)->getSourceRange()); + } + return false; + } + } + int maxElements; + if (DeclType->isIncompleteArrayType()) { + // FIXME: use a proper constant + maxElements = 0x7FFFFFFF; + } else if (const VariableArrayType *VAT = + DeclType->getAsVariableArrayType()) { + // Check for VLAs; in standard C it would be possible to check this + // earlier, but I don't know where clang accepts VLAs (gcc accepts + // them in all sorts of strange places). + Diag(VAT->getSizeExpr()->getLocStart(), + diag::err_variable_object_no_init, + VAT->getSizeExpr()->getSourceRange()); + hadError = true; + maxElements = 0x7FFFFFFF; + } else { + const ConstantArrayType *CAT = DeclType->getAsConstantArrayType(); + maxElements = static_cast(CAT->getSize().getZExtValue()); + } + QualType elementType = DeclType->getAsArrayType()->getElementType(); + int numElements = 0; + for (int i = 0; i < maxElements; ++i, ++numElements) { + // Don't attempt to go past the end of the init list + if (startIndex >= IList->getNumInits()) + break; + Expr* expr = IList->getInit(startIndex); + if (InitListExpr *SubInitList = dyn_cast(expr)) { + unsigned newIndex = 0; + hadError |= CheckInitializerListTypes(SubInitList, elementType, + true, newIndex); + ++startIndex; + } else { + hadError |= CheckInitializerListTypes(IList, elementType, + false, startIndex); + } + } + if (DeclType->isIncompleteArrayType()) { + // If this is an incomplete array type, the actual type needs to + // be calculated here + if (numElements == 0) { + // Sizing an array implicitly to zero is not allowed + // (It could in theory be allowed, but it doesn't really matter.) + Diag(IList->getLocStart(), + diag::err_at_least_one_initializer_needed_to_size_array); + hadError = true; + } else { + llvm::APSInt ConstVal(32); + ConstVal = numElements; + DeclType = Context.getConstantArrayType(elementType, ConstVal, + ArrayType::Normal, 0); + } + } + } else { + assert(0 && "Aggregate that isn't a function or array?!"); + } + } else { + // In C, all types are either scalars or aggregates, but + // additional handling is needed here for C++ (and possibly others?). + assert(0 && "Unsupported initializer type"); + } + + // If this init list is a base list, we set the type; an initializer doesn't + // fundamentally have a type, but this makes the ASTs a bit easier to read + if (topLevel) + IList->setType(DeclType); + + if (topLevel && startIndex < IList->getNumInits()) { + // We have leftover initializers; warn + Diag(IList->getInit(startIndex)->getLocStart(), + diag::warn_excess_initializers, + IList->getInit(startIndex)->getSourceRange()); + } + return hadError; +} + +bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { + // C99 6.7.8p3: The type of the entity to be initialized shall be an array + // of unknown size ("[]") or an object type that is not a variable array type. + if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) + return Diag(VAT->getSizeExpr()->getLocStart(), + diag::err_variable_object_no_init, + VAT->getSizeExpr()->getSourceRange()); + + InitListExpr *InitList = dyn_cast(Init); + if (!InitList) { + // FIXME: Handle wide strings + if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType)) + return CheckStringLiteralInit(strLiteral, DeclType); + + if (DeclType->isArrayType()) + return Diag(Init->getLocStart(), + diag::err_array_init_list_required, + Init->getSourceRange()); + + return CheckSingleInitializer(Init, DeclType); + } + unsigned newIndex = 0; + return CheckInitializerListTypes(InitList, DeclType, true, newIndex); +} + +Sema::DeclTy * +Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { + ScopedDecl *LastDeclarator = dyn_cast_or_null((Decl *)lastDecl); + IdentifierInfo *II = D.getIdentifier(); + + // All of these full declarators require an identifier. If it doesn't have + // one, the ParsedFreeStandingDeclSpec action should be used. + if (II == 0) { + Diag(D.getDeclSpec().getSourceRange().getBegin(), + diag::err_declarator_need_ident, + D.getDeclSpec().getSourceRange(), D.getSourceRange()); + return 0; + } + + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0) + S = S->getParent(); + + // See if this is a redefinition of a variable in the same scope. + ScopedDecl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary, + D.getIdentifierLoc(), S); + ScopedDecl *New; + bool InvalidDecl = false; + + QualType R = GetTypeForDeclarator(D, S); + assert(!R.isNull() && "GetTypeForDeclarator() returned null type"); + + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator); + if (!NewTD) return 0; + + // Handle attributes prior to checking for duplicates in MergeVarDecl + HandleDeclAttributes(NewTD, D.getDeclSpec().getAttributes(), + D.getAttributes()); + // Merge the decl with the existing one if appropriate. If the decl is + // in an outer scope, it isn't the same thing. + if (PrevDecl && S->isDeclScope(PrevDecl)) { + NewTD = MergeTypeDefDecl(NewTD, PrevDecl); + if (NewTD == 0) return 0; + } + New = NewTD; + if (S->getParent() == 0) { + // C99 6.7.7p2: If a typedef name specifies a variably modified type + // then it shall have block scope. + if (NewTD->getUnderlyingType()->isVariablyModifiedType()) { + // FIXME: Diagnostic needs to be fixed. + Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla); + InvalidDecl = true; + } + } + } else if (R.getTypePtr()->isFunctionType()) { + FunctionDecl::StorageClass SC = FunctionDecl::None; + switch (D.getDeclSpec().getStorageClassSpec()) { + default: assert(0 && "Unknown storage class!"); + case DeclSpec::SCS_auto: + case DeclSpec::SCS_register: + Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func, + R.getAsString()); + InvalidDecl = true; + break; + case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break; + case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break; + case DeclSpec::SCS_static: SC = FunctionDecl::Static; break; + case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break; + } + + bool isInline = D.getDeclSpec().isInlineSpecified(); + FunctionDecl *NewFD = FunctionDecl::Create(Context, D.getIdentifierLoc(), + II, R, SC, isInline, + LastDeclarator); + // Handle attributes. + HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(), + D.getAttributes()); + + // Merge the decl with the existing one if appropriate. Since C functions + // are in a flat namespace, make sure we consider decls in outer scopes. + if (PrevDecl) { + NewFD = MergeFunctionDecl(NewFD, PrevDecl); + if (NewFD == 0) return 0; + } + New = NewFD; + } else { + if (R.getTypePtr()->isObjCInterfaceType()) { + Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object, + D.getIdentifier()->getName()); + InvalidDecl = true; + } + + VarDecl *NewVD; + VarDecl::StorageClass SC; + switch (D.getDeclSpec().getStorageClassSpec()) { + default: assert(0 && "Unknown storage class!"); + case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; + case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; + case DeclSpec::SCS_static: SC = VarDecl::Static; break; + case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; + case DeclSpec::SCS_register: SC = VarDecl::Register; break; + case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; + } + if (S->getParent() == 0) { + // C99 6.9p2: The storage-class specifiers auto and register shall not + // appear in the declaration specifiers in an external declaration. + if (SC == VarDecl::Auto || SC == VarDecl::Register) { + Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope, + R.getAsString()); + InvalidDecl = true; + } + NewVD = FileVarDecl::Create(Context, D.getIdentifierLoc(), II, R, SC, + LastDeclarator); + } else { + NewVD = BlockVarDecl::Create(Context, D.getIdentifierLoc(), II, R, SC, + LastDeclarator); + } + // Handle attributes prior to checking for duplicates in MergeVarDecl + HandleDeclAttributes(NewVD, D.getDeclSpec().getAttributes(), + D.getAttributes()); + + // Emit an error if an address space was applied to decl with local storage. + // This includes arrays of objects with address space qualifiers, but not + // automatic variables that point to other address spaces. + // ISO/IEC TR 18037 S5.1.2 + if (NewVD->hasLocalStorage()) { + QualType AutoTy = NewVD->getCanonicalType(); + if (const ArrayType *AT = AutoTy->getAsArrayType()) + AutoTy = AT->getElementType().getCanonicalType(); + if (AutoTy.getAddressSpace() != 0) { + Diag(D.getIdentifierLoc(), diag::err_as_qualified_auto_decl); + InvalidDecl = true; + } + } + // Merge the decl with the existing one if appropriate. If the decl is + // in an outer scope, it isn't the same thing. + if (PrevDecl && S->isDeclScope(PrevDecl)) { + NewVD = MergeVarDecl(NewVD, PrevDecl); + if (NewVD == 0) return 0; + } + New = NewVD; + } + + // If this has an identifier, add it to the scope stack. + if (II) { + New->setNext(II->getFETokenInfo()); + II->setFETokenInfo(New); + S->AddDecl(New); + } + // If any semantic error occurred, mark the decl as invalid. + if (D.getInvalidType() || InvalidDecl) + New->setInvalidDecl(); + + return New; +} + +bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { + SourceLocation loc; + // FIXME: Remove the isReference check and handle assignment to a reference. + if (!DclT->isReferenceType() && !Init->isConstantExpr(Context, &loc)) { + assert(loc.isValid() && "isConstantExpr didn't return a loc!"); + Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange()); + return true; + } + return false; +} + +void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { + Decl *RealDecl = static_cast(dcl); + Expr *Init = static_cast(init); + assert(Init && "missing initializer"); + + // If there is no declaration, there was an error parsing it. Just ignore + // the initializer. + if (RealDecl == 0) { + delete Init; + return; + } + + VarDecl *VDecl = dyn_cast(RealDecl); + if (!VDecl) { + Diag(dyn_cast(RealDecl)->getLocation(), + diag::err_illegal_initializer); + RealDecl->setInvalidDecl(); + return; + } + // Get the decls type and save a reference for later, since + // CheckInitializerTypes may change it. + QualType DclT = VDecl->getType(), SavT = DclT; + if (BlockVarDecl *BVD = dyn_cast(VDecl)) { + VarDecl::StorageClass SC = BVD->getStorageClass(); + if (SC == VarDecl::Extern) { // C99 6.7.8p5 + Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); + BVD->setInvalidDecl(); + } else if (!BVD->isInvalidDecl()) { + if (CheckInitializerTypes(Init, DclT)) + BVD->setInvalidDecl(); + if (SC == VarDecl::Static) // C99 6.7.8p4. + CheckForConstantInitializer(Init, DclT); + } + } else if (FileVarDecl *FVD = dyn_cast(VDecl)) { + if (FVD->getStorageClass() == VarDecl::Extern) + Diag(VDecl->getLocation(), diag::warn_extern_init); + if (!FVD->isInvalidDecl()) + if (CheckInitializerTypes(Init, DclT)) + FVD->setInvalidDecl(); + + // C99 6.7.8p4. All file scoped initializers need to be constant. + CheckForConstantInitializer(Init, DclT); + } + // If the type changed, it means we had an incomplete type that was + // completed by the initializer. For example: + // int ary[] = { 1, 3, 5 }; + // "ary" transitions from a VariableArrayType to a ConstantArrayType. + if (!VDecl->isInvalidDecl() && (DclT != SavT)) { + VDecl->setType(DclT); + Init->setType(DclT); + } + + // Attach the initializer to the decl. + VDecl->setInit(Init); + return; +} + +/// The declarators are chained together backwards, reverse the list. +Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { + // Often we have single declarators, handle them quickly. + Decl *GroupDecl = static_cast(group); + if (GroupDecl == 0) + return 0; + + ScopedDecl *Group = dyn_cast(GroupDecl); + ScopedDecl *NewGroup = 0; + if (Group->getNextDeclarator() == 0) + NewGroup = Group; + else { // reverse the list. + while (Group) { + ScopedDecl *Next = Group->getNextDeclarator(); + Group->setNextDeclarator(NewGroup); + NewGroup = Group; + Group = Next; + } + } + // Perform semantic analysis that depends on having fully processed both + // the declarator and initializer. + for (ScopedDecl *ID = NewGroup; ID; ID = ID->getNextDeclarator()) { + VarDecl *IDecl = dyn_cast(ID); + if (!IDecl) + continue; + FileVarDecl *FVD = dyn_cast(IDecl); + BlockVarDecl *BVD = dyn_cast(IDecl); + QualType T = IDecl->getType(); + + // C99 6.7.5.2p2: If an identifier is declared to be an object with + // static storage duration, it shall not have a variable length array. + if ((FVD || BVD) && IDecl->getStorageClass() == VarDecl::Static) { + if (T->getAsVariableArrayType()) { + Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla); + IDecl->setInvalidDecl(); + } + } + // Block scope. C99 6.7p7: If an identifier for an object is declared with + // no linkage (C99 6.2.2p6), the type for the object shall be complete... + if (BVD && IDecl->getStorageClass() != VarDecl::Extern) { + if (T->isIncompleteType()) { + Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type, + T.getAsString()); + IDecl->setInvalidDecl(); + } + } + // File scope. C99 6.9.2p2: A declaration of an identifier for and + // object that has file scope without an initializer, and without a + // storage-class specifier or with the storage-class specifier "static", + // constitutes a tentative definition. Note: A tentative definition with + // external linkage is valid (C99 6.2.2p5). + if (FVD && !FVD->getInit() && (FVD->getStorageClass() == VarDecl::Static || + FVD->getStorageClass() == VarDecl::None)) { + if (T->isIncompleteArrayType()) { + // C99 6.9.2 (p2, p5): Implicit initialization causes an incomplete + // array to be completed. Don't issue a diagnostic. + } else if (T->isIncompleteType()) { + // C99 6.9.2p3: If the declaration of an identifier for an object is + // a tentative definition and has internal linkage (C99 6.2.2p3), the + // declared type shall not be an incomplete type. + Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type, + T.getAsString()); + IDecl->setInvalidDecl(); + } + } + } + return NewGroup; +} + +// Called from Sema::ParseStartOfFunctionDef(). +ParmVarDecl * +Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, + Scope *FnScope) { + IdentifierInfo *II = PI.Ident; + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. + // Can this happen for params? We already checked that they don't conflict + // among each other. Here they can only shadow globals, which is ok. + if (/*Decl *PrevDecl = */LookupScopedDecl(II, Decl::IDNS_Ordinary, + PI.IdentLoc, FnScope)) { + + } + + // FIXME: Handle storage class (auto, register). No declarator? + // TODO: Chain to previous parameter with the prevdeclarator chain? + + // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). + // Doing the promotion here has a win and a loss. The win is the type for + // both Decl's and DeclRefExpr's will match (a convenient invariant for the + // code generator). The loss is the orginal type isn't preserved. For example: + // + // void func(int parmvardecl[5]) { // convert "int [5]" to "int *" + // int blockvardecl[5]; + // sizeof(parmvardecl); // size == 4 + // sizeof(blockvardecl); // size == 20 + // } + // + // For expressions, all implicit conversions are captured using the + // ImplicitCastExpr AST node (we have no such mechanism for Decl's). + // + // FIXME: If a source translation tool needs to see the original type, then + // we need to consider storing both types (in ParmVarDecl)... + // + QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo); + if (const ArrayType *AT = parmDeclType->getAsArrayType()) { + // int x[restrict 4] -> int *restrict + parmDeclType = Context.getPointerType(AT->getElementType()); + parmDeclType = parmDeclType.getQualifiedType(AT->getIndexTypeQualifier()); + } else if (parmDeclType->isFunctionType()) + parmDeclType = Context.getPointerType(parmDeclType); + + ParmVarDecl *New = ParmVarDecl::Create(Context, PI.IdentLoc, II, parmDeclType, + VarDecl::None, 0); + + if (PI.InvalidType) + New->setInvalidDecl(); + + // If this has an identifier, add it to the scope stack. + if (II) { + New->setNext(II->getFETokenInfo()); + II->setFETokenInfo(New); + FnScope->AddDecl(New); + } + + HandleDeclAttributes(New, PI.AttrList, 0); + return New; +} + +Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { + assert(CurFunctionDecl == 0 && "Function parsing confused"); + assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && + "Not a function declarator!"); + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' + // for a K&R function. + if (!FTI.hasPrototype) { + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + if (FTI.ArgInfo[i].TypeInfo == 0) { + Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared, + FTI.ArgInfo[i].Ident->getName()); + // Implicitly declare the argument as type 'int' for lack of a better + // type. + FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr(); + } + } + + // Since this is a function definition, act as though we have information + // about the arguments. + if (FTI.NumArgs) + FTI.hasPrototype = true; + } else { + // FIXME: Diagnose arguments without names in C. + + } + + Scope *GlobalScope = FnBodyScope->getParent(); + + // See if this is a redefinition. + ScopedDecl *PrevDcl = LookupScopedDecl(D.getIdentifier(), Decl::IDNS_Ordinary, + D.getIdentifierLoc(), GlobalScope); + if (FunctionDecl *FD = dyn_cast_or_null(PrevDcl)) { + if (FD->getBody()) { + Diag(D.getIdentifierLoc(), diag::err_redefinition, + D.getIdentifier()->getName()); + Diag(FD->getLocation(), diag::err_previous_definition); + } + } + Decl *decl = static_cast(ActOnDeclarator(GlobalScope, D, 0)); + FunctionDecl *FD = cast(decl); + CurFunctionDecl = FD; + + // Create Decl objects for each parameter, adding them to the FunctionDecl. + llvm::SmallVector Params; + + // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes + // no arguments, not a function that takes a single void argument. + if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + !QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo).getCVRQualifiers() && + QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo)->isVoidType()) { + // empty arg list, don't push any params. + } else { + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + Params.push_back(ActOnParamDeclarator(D.getTypeObject(0).Fun.ArgInfo[i], + FnBodyScope)); + } + } + + FD->setParams(&Params[0], Params.size()); + + return FD; +} + +Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtTy *Body) { + Decl *dcl = static_cast(D); + if (FunctionDecl *FD = dyn_cast(dcl)) { + FD->setBody((Stmt*)Body); + assert(FD == CurFunctionDecl && "Function parsing confused"); + CurFunctionDecl = 0; + } else if (ObjCMethodDecl *MD = dyn_cast(dcl)) { + MD->setBody((Stmt*)Body); + CurMethodDecl = 0; + } + // Verify and clean out per-function state. + + // Check goto/label use. + for (llvm::DenseMap::iterator + I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) { + // Verify that we have no forward references left. If so, there was a goto + // or address of a label taken, but no definition of it. Label fwd + // definitions are indicated with a null substmt. + if (I->second->getSubStmt() == 0) { + LabelStmt *L = I->second; + // Emit error. + Diag(L->getIdentLoc(), diag::err_undeclared_label_use, L->getName()); + + // At this point, we have gotos that use the bogus label. Stitch it into + // the function body so that they aren't leaked and that the AST is well + // formed. + if (Body) { + L->setSubStmt(new NullStmt(L->getIdentLoc())); + cast((Stmt*)Body)->push_back(L); + } else { + // The whole function wasn't parsed correctly, just delete this. + delete L; + } + } + } + LabelMap.clear(); + + return D; +} + +/// ImplicitlyDefineFunction - An undeclared identifier was used in a function +/// call, forming a call to an implicitly defined function (per C99 6.5.1p2). +ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, + IdentifierInfo &II, Scope *S) { + if (getLangOptions().C99) // Extension in C99. + Diag(Loc, diag::ext_implicit_function_decl, II.getName()); + else // Legal in C90, but warn about it. + Diag(Loc, diag::warn_implicit_function_decl, II.getName()); + + // FIXME: handle stuff like: + // void foo() { extern float X(); } + // void bar() { X(); } <-- implicit decl for X in another scope. + + // Set a Declarator for the implicit definition: int foo(); + const char *Dummy; + DeclSpec DS; + bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy); + Error = Error; // Silence warning. + assert(!Error && "Error setting up implicit decl!"); + Declarator D(DS, Declarator::BlockContext); + D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, Loc)); + D.SetIdentifier(&II, Loc); + + // Find translation-unit scope to insert this function into. + if (Scope *FnS = S->getFnParent()) + S = FnS->getParent(); // Skip all scopes in a function at once. + while (S->getParent()) + S = S->getParent(); + + return dyn_cast(static_cast(ActOnDeclarator(S, D, 0))); +} + + +TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + ScopedDecl *LastDeclarator) { + assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); + assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + + // Scope manipulation handled by caller. + TypedefDecl *NewTD = TypedefDecl::Create(Context, D.getIdentifierLoc(), + D.getIdentifier(), + T, LastDeclarator); + if (D.getInvalidType()) + NewTD->setInvalidDecl(); + return NewTD; +} + +/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the +/// former case, Name will be non-null. In the later case, Name will be null. +/// TagType indicates what kind of tag this is. TK indicates whether this is a +/// reference/declaration/definition of a tag. +Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, + SourceLocation KWLoc, IdentifierInfo *Name, + SourceLocation NameLoc, AttributeList *Attr) { + // If this is a use of an existing tag, it must have a name. + assert((Name != 0 || TK == TK_Definition) && + "Nameless record must be a definition!"); + + Decl::Kind Kind; + switch (TagType) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = Decl::Struct; break; + case DeclSpec::TST_union: Kind = Decl::Union; break; +//case DeclSpec::TST_class: Kind = Decl::Class; break; + case DeclSpec::TST_enum: Kind = Decl::Enum; break; + } + + // If this is a named struct, check to see if there was a previous forward + // declaration or definition. + if (TagDecl *PrevDecl = + dyn_cast_or_null(LookupScopedDecl(Name, Decl::IDNS_Tag, + NameLoc, S))) { + + // If this is a use of a previous tag, or if the tag is already declared in + // the same scope (so that the definition/declaration completes or + // rementions the tag), reuse the decl. + if (TK == TK_Reference || S->isDeclScope(PrevDecl)) { + // Make sure that this wasn't declared as an enum and now used as a struct + // or something similar. + if (PrevDecl->getKind() != Kind) { + Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_use); + } + + // If this is a use or a forward declaration, we're good. + if (TK != TK_Definition) + return PrevDecl; + + // Diagnose attempts to redefine a tag. + if (PrevDecl->isDefinition()) { + Diag(NameLoc, diag::err_redefinition, Name->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + // If this is a redefinition, recover by making this struct be + // anonymous, which will make any later references get the previous + // definition. + Name = 0; + } else { + // Okay, this is definition of a previously declared or referenced tag. + // Move the location of the decl to be the definition site. + PrevDecl->setLocation(NameLoc); + return PrevDecl; + } + } + // If we get here, this is a definition of a new struct type in a nested + // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new + // type. + } + + // If there is an identifier, use the location of the identifier as the + // location of the decl, otherwise use the location of the struct/union + // keyword. + SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; + + // Otherwise, if this is the first time we've seen this tag, create the decl. + TagDecl *New; + switch (Kind) { + default: assert(0 && "Unknown tag kind!"); + case Decl::Enum: + // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: + // enum X { A, B, C } D; D should chain to X. + New = EnumDecl::Create(Context, Loc, Name, 0); + // If this is an undefined enum, warn. + if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum); + break; + case Decl::Union: + case Decl::Struct: + case Decl::Class: + // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: + // struct X { int A; } D; D should chain to X. + New = RecordDecl::Create(Context, Kind, Loc, Name, 0); + break; + } + + // If this has an identifier, add it to the scope stack. + if (Name) { + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0) + S = S->getParent(); + + // Add it to the decl chain. + New->setNext(Name->getFETokenInfo()); + Name->setFETokenInfo(New); + S->AddDecl(New); + } + + HandleDeclAttributes(New, Attr, 0); + return New; +} + +/// ActOnField - Each field of a struct/union/class is passed into this in order +/// to create a FieldDecl object for it. +Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagDecl, + SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { + IdentifierInfo *II = D.getIdentifier(); + Expr *BitWidth = (Expr*)BitfieldWidth; + SourceLocation Loc = DeclStart; + if (II) Loc = D.getIdentifierLoc(); + + // FIXME: Unnamed fields can be handled in various different ways, for + // example, unnamed unions inject all members into the struct namespace! + + + if (BitWidth) { + // TODO: Validate. + //printf("WARNING: BITFIELDS IGNORED!\n"); + + // 6.7.2.1p3 + // 6.7.2.1p4 + + } else { + // Not a bitfield. + + // validate II. + + } + + QualType T = GetTypeForDeclarator(D, S); + assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + bool InvalidDecl = false; + + // C99 6.7.2.1p8: A member of a structure or union may have any type other + // than a variably modified type. + if (T->isVariablyModifiedType()) { + // FIXME: This diagnostic needs work + Diag(Loc, diag::err_typecheck_illegal_vla, Loc); + InvalidDecl = true; + } + // FIXME: Chain fielddecls together. + FieldDecl *NewFD; + + if (isa(static_cast(TagDecl))) + NewFD = new FieldDecl(Loc, II, T, BitWidth); + else if (isa(static_cast(TagDecl)) || + isa(static_cast(TagDecl)) || + isa(static_cast(TagDecl)) || + // FIXME: ivars are currently used to model properties, and + // properties can appear within a protocol. + // See corresponding FIXME in DeclObjC.h:ObjCPropertyDecl. + isa(static_cast(TagDecl))) + NewFD = new ObjCIvarDecl(Loc, II, T); + else + assert(0 && "Sema::ActOnField(): Unknown TagDecl"); + + HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(), + D.getAttributes()); + + if (D.getInvalidType() || InvalidDecl) + NewFD->setInvalidDecl(); + return NewFD; +} + +/// TranslateIvarVisibility - Translate visibility from a token ID to an +/// AST enum value. +static ObjCIvarDecl::AccessControl +TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { + switch (ivarVisibility) { + case tok::objc_private: return ObjCIvarDecl::Private; + case tok::objc_public: return ObjCIvarDecl::Public; + case tok::objc_protected: return ObjCIvarDecl::Protected; + case tok::objc_package: return ObjCIvarDecl::Package; + default: assert(false && "Unknown visitibility kind"); + } +} + +void Sema::ActOnFields(Scope* S, + SourceLocation RecLoc, DeclTy *RecDecl, + DeclTy **Fields, unsigned NumFields, + SourceLocation LBrac, SourceLocation RBrac, + tok::ObjCKeywordKind *visibility) { + Decl *EnclosingDecl = static_cast(RecDecl); + assert(EnclosingDecl && "missing record or interface decl"); + RecordDecl *Record = dyn_cast(EnclosingDecl); + + if (Record && Record->isDefinition()) { + // Diagnose code like: + // struct S { struct S {} X; }; + // We discover this when we complete the outer S. Reject and ignore the + // outer S. + Diag(Record->getLocation(), diag::err_nested_redefinition, + Record->getKindName()); + Diag(RecLoc, diag::err_previous_definition); + Record->setInvalidDecl(); + return; + } + // Verify that all the fields are okay. + unsigned NumNamedMembers = 0; + llvm::SmallVector RecFields; + llvm::SmallSet FieldIDs; + + for (unsigned i = 0; i != NumFields; ++i) { + + FieldDecl *FD = cast_or_null(static_cast(Fields[i])); + assert(FD && "missing field decl"); + + // Remember all fields. + RecFields.push_back(FD); + + // Get the type for the field. + Type *FDTy = FD->getType().getTypePtr(); + + // If we have visibility info, make sure the AST is set accordingly. + if (visibility) + cast(FD)->setAccessControl( + TranslateIvarVisibility(visibility[i])); + + // C99 6.7.2.1p2 - A field may not be a function type. + if (FDTy->isFunctionType()) { + Diag(FD->getLocation(), diag::err_field_declared_as_function, + FD->getName()); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // C99 6.7.2.1p2 - A field may not be an incomplete type except... + if (FDTy->isIncompleteType()) { + if (!Record) { // Incomplete ivar type is always an error. + Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName()); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + if (i != NumFields-1 || // ... that the last member ... + Record->getKind() != Decl::Struct || // ... of a structure ... + !FDTy->isArrayType()) { //... may have incomplete array type. + Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName()); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + if (NumNamedMembers < 1) { //... must have more than named member ... + Diag(FD->getLocation(), diag::err_flexible_array_empty_struct, + FD->getName()); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Okay, we have a legal flexible array member at the end of the struct. + if (Record) + Record->setHasFlexibleArrayMember(true); + } + /// C99 6.7.2.1p2 - a struct ending in a flexible array member cannot be the + /// field of another structure or the element of an array. + if (const RecordType *FDTTy = FDTy->getAsRecordType()) { + if (FDTTy->getDecl()->hasFlexibleArrayMember()) { + // If this is a member of a union, then entire union becomes "flexible". + if (Record && Record->getKind() == Decl::Union) { + Record->setHasFlexibleArrayMember(true); + } else { + // If this is a struct/class and this is not the last element, reject + // it. Note that GCC supports variable sized arrays in the middle of + // structures. + if (i != NumFields-1) { + Diag(FD->getLocation(), diag::err_variable_sized_type_in_struct, + FD->getName()); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // We support flexible arrays at the end of structs in other structs + // as an extension. + Diag(FD->getLocation(), diag::ext_flexible_array_in_struct, + FD->getName()); + if (Record) + Record->setHasFlexibleArrayMember(true); + } + } + } + /// A field cannot be an Objective-c object + if (FDTy->isObjCInterfaceType()) { + Diag(FD->getLocation(), diag::err_statically_allocated_object, + FD->getName()); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Keep track of the number of named members. + if (IdentifierInfo *II = FD->getIdentifier()) { + // Detect duplicate member names. + if (!FieldIDs.insert(II)) { + Diag(FD->getLocation(), diag::err_duplicate_member, II->getName()); + // Find the previous decl. + SourceLocation PrevLoc; + for (unsigned i = 0, e = RecFields.size(); ; ++i) { + assert(i != e && "Didn't find previous def!"); + if (RecFields[i]->getIdentifier() == II) { + PrevLoc = RecFields[i]->getLocation(); + break; + } + } + Diag(PrevLoc, diag::err_previous_definition); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + ++NumNamedMembers; + } + } + + // Okay, we successfully defined 'Record'. + if (Record) { + Record->defineBody(&RecFields[0], RecFields.size()); + Consumer.HandleTagDeclDefinition(Record); + } else { + ObjCIvarDecl **ClsFields = reinterpret_cast(&RecFields[0]); + if (ObjCInterfaceDecl *ID = dyn_cast(EnclosingDecl)) + ID->addInstanceVariablesToClass(ClsFields, RecFields.size(), RBrac); + else if (ObjCImplementationDecl *IMPDecl = + dyn_cast(EnclosingDecl)) { + assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); + IMPDecl->ObjCAddInstanceVariablesToClassImpl(ClsFields, RecFields.size()); + CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); + } + } +} + +Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, + DeclTy *lastEnumConst, + SourceLocation IdLoc, IdentifierInfo *Id, + SourceLocation EqualLoc, ExprTy *val) { + theEnumDecl = theEnumDecl; // silence unused warning. + EnumConstantDecl *LastEnumConst = + cast_or_null(static_cast(lastEnumConst)); + Expr *Val = static_cast(val); + + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0) + S = S->getParent(); + + // Verify that there isn't already something declared with this name in this + // scope. + if (ScopedDecl *PrevDecl = LookupScopedDecl(Id, Decl::IDNS_Ordinary, + IdLoc, S)) { + if (S->isDeclScope(PrevDecl)) { + if (isa(PrevDecl)) + Diag(IdLoc, diag::err_redefinition_of_enumerator, Id->getName()); + else + Diag(IdLoc, diag::err_redefinition, Id->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + delete Val; + return 0; + } + } + + llvm::APSInt EnumVal(32); + QualType EltTy; + if (Val) { + // Make sure to promote the operand type to int. + UsualUnaryConversions(Val); + + // C99 6.7.2.2p2: Make sure we have an integer constant expression. + SourceLocation ExpLoc; + if (!Val->isIntegerConstantExpr(EnumVal, Context, &ExpLoc)) { + Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr, + Id->getName()); + delete Val; + Val = 0; // Just forget about it. + } else { + EltTy = Val->getType(); + } + } + + if (!Val) { + if (LastEnumConst) { + // Assign the last value + 1. + EnumVal = LastEnumConst->getInitVal(); + ++EnumVal; + + // Check for overflow on increment. + if (EnumVal < LastEnumConst->getInitVal()) + Diag(IdLoc, diag::warn_enum_value_overflow); + + EltTy = LastEnumConst->getType(); + } else { + // First value, set to zero. + EltTy = Context.IntTy; + EnumVal.zextOrTrunc(static_cast(Context.getTypeSize(EltTy))); + } + } + + EnumConstantDecl *New = + EnumConstantDecl::Create(Context, IdLoc, Id, EltTy, Val, EnumVal, + LastEnumConst); + + // Register this decl in the current scope stack. + New->setNext(Id->getFETokenInfo()); + Id->setFETokenInfo(New); + S->AddDecl(New); + return New; +} + +void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, + DeclTy **Elements, unsigned NumElements) { + EnumDecl *Enum = cast(static_cast(EnumDeclX)); + assert(!Enum->isDefinition() && "Enum redefinitions can't reach here"); + + // TODO: If the result value doesn't fit in an int, it must be a long or long + // long value. ISO C does not support this, but GCC does as an extension, + // emit a warning. + unsigned IntWidth = Context.Target.getIntWidth(); + + // Verify that all the values are okay, compute the size of the values, and + // reverse the list. + unsigned NumNegativeBits = 0; + unsigned NumPositiveBits = 0; + + // Keep track of whether all elements have type int. + bool AllElementsInt = true; + + EnumConstantDecl *EltList = 0; + for (unsigned i = 0; i != NumElements; ++i) { + EnumConstantDecl *ECD = + cast_or_null(static_cast(Elements[i])); + if (!ECD) continue; // Already issued a diagnostic. + + // If the enum value doesn't fit in an int, emit an extension warning. + const llvm::APSInt &InitVal = ECD->getInitVal(); + assert(InitVal.getBitWidth() >= IntWidth && + "Should have promoted value to int"); + if (InitVal.getBitWidth() > IntWidth) { + llvm::APSInt V(InitVal); + V.trunc(IntWidth); + V.extend(InitVal.getBitWidth()); + if (V != InitVal) + Diag(ECD->getLocation(), diag::ext_enum_value_not_int, + InitVal.toString()); + } + + // Keep track of the size of positive and negative values. + if (InitVal.isUnsigned() || InitVal.isNonNegative()) + NumPositiveBits = std::max(NumPositiveBits, + (unsigned)InitVal.getActiveBits()); + else + NumNegativeBits = std::max(NumNegativeBits, + (unsigned)InitVal.getMinSignedBits()); + + // Keep track of whether every enum element has type int (very commmon). + if (AllElementsInt) + AllElementsInt = ECD->getType() == Context.IntTy; + + ECD->setNextDeclarator(EltList); + EltList = ECD; + } + + // Figure out the type that should be used for this enum. + // FIXME: Support attribute(packed) on enums and -fshort-enums. + QualType BestType; + unsigned BestWidth; + + if (NumNegativeBits) { + // If there is a negative value, figure out the smallest integer type (of + // int/long/longlong) that fits. + if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { + BestType = Context.IntTy; + BestWidth = IntWidth; + } else { + BestWidth = Context.Target.getLongWidth(); + + if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) + BestType = Context.LongTy; + else { + BestWidth = Context.Target.getLongLongWidth(); + + if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) + Diag(Enum->getLocation(), diag::warn_enum_too_large); + BestType = Context.LongLongTy; + } + } + } else { + // If there is no negative value, figure out which of uint, ulong, ulonglong + // fits. + if (NumPositiveBits <= IntWidth) { + BestType = Context.UnsignedIntTy; + BestWidth = IntWidth; + } else if (NumPositiveBits <= + (BestWidth = Context.Target.getLongWidth())) { + BestType = Context.UnsignedLongTy; + } else { + BestWidth = Context.Target.getLongLongWidth(); + assert(NumPositiveBits <= BestWidth && + "How could an initializer get larger than ULL?"); + BestType = Context.UnsignedLongLongTy; + } + } + + // Loop over all of the enumerator constants, changing their types to match + // the type of the enum if needed. + for (unsigned i = 0; i != NumElements; ++i) { + EnumConstantDecl *ECD = + cast_or_null(static_cast(Elements[i])); + if (!ECD) continue; // Already issued a diagnostic. + + // Standard C says the enumerators have int type, but we allow, as an + // extension, the enumerators to be larger than int size. If each + // enumerator value fits in an int, type it as an int, otherwise type it the + // same as the enumerator decl itself. This means that in "enum { X = 1U }" + // that X has type 'int', not 'unsigned'. + if (ECD->getType() == Context.IntTy) { + // Make sure the init value is signed. + llvm::APSInt IV = ECD->getInitVal(); + IV.setIsSigned(true); + ECD->setInitVal(IV); + continue; // Already int type. + } + + // Determine whether the value fits into an int. + llvm::APSInt InitVal = ECD->getInitVal(); + bool FitsInInt; + if (InitVal.isUnsigned() || !InitVal.isNegative()) + FitsInInt = InitVal.getActiveBits() < IntWidth; + else + FitsInInt = InitVal.getMinSignedBits() <= IntWidth; + + // If it fits into an integer type, force it. Otherwise force it to match + // the enum decl type. + QualType NewTy; + unsigned NewWidth; + bool NewSign; + if (FitsInInt) { + NewTy = Context.IntTy; + NewWidth = IntWidth; + NewSign = true; + } else if (ECD->getType() == BestType) { + // Already the right type! + continue; + } else { + NewTy = BestType; + NewWidth = BestWidth; + NewSign = BestType->isSignedIntegerType(); + } + + // Adjust the APSInt value. + InitVal.extOrTrunc(NewWidth); + InitVal.setIsSigned(NewSign); + ECD->setInitVal(InitVal); + + // Adjust the Expr initializer and type. + ECD->setInitExpr(new ImplicitCastExpr(NewTy, ECD->getInitExpr())); + ECD->setType(NewTy); + } + + Enum->defineElements(EltList, BestType); + Consumer.HandleTagDeclDefinition(Enum); +} + +Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, + ExprTy *expr) { + StringLiteral *AsmString = cast((Expr*)expr); + + return new FileScopeAsmDecl(Loc, AsmString); +} + +Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc, + SourceLocation LBrace, + SourceLocation RBrace, + const char *Lang, + unsigned StrSize, + DeclTy *D) { + LinkageSpecDecl::LanguageIDs Language; + Decl *dcl = static_cast(D); + if (strncmp(Lang, "\"C\"", StrSize) == 0) + Language = LinkageSpecDecl::lang_c; + else if (strncmp(Lang, "\"C++\"", StrSize) == 0) + Language = LinkageSpecDecl::lang_cxx; + else { + Diag(Loc, diag::err_bad_language); + return 0; + } + + // FIXME: Add all the various semantics of linkage specifications + return new LinkageSpecDecl(Loc, Language, dcl); +} + +void Sema::HandleDeclAttribute(Decl *New, AttributeList *Attr) { + + switch (Attr->getKind()) { + case AttributeList::AT_vector_size: + if (ValueDecl *vDecl = dyn_cast(New)) { + QualType newType = HandleVectorTypeAttribute(vDecl->getType(), Attr); + if (!newType.isNull()) // install the new vector type into the decl + vDecl->setType(newType); + } + if (TypedefDecl *tDecl = dyn_cast(New)) { + QualType newType = HandleVectorTypeAttribute(tDecl->getUnderlyingType(), + Attr); + if (!newType.isNull()) // install the new vector type into the decl + tDecl->setUnderlyingType(newType); + } + break; + case AttributeList::AT_ocu_vector_type: + if (TypedefDecl *tDecl = dyn_cast(New)) + HandleOCUVectorTypeAttribute(tDecl, Attr); + else + Diag(Attr->getLoc(), + diag::err_typecheck_ocu_vector_not_typedef); + break; + case AttributeList::AT_address_space: + if (TypedefDecl *tDecl = dyn_cast(New)) { + QualType newType = HandleAddressSpaceTypeAttribute( + tDecl->getUnderlyingType(), + Attr); + tDecl->setUnderlyingType(newType); + } else if (ValueDecl *vDecl = dyn_cast(New)) { + QualType newType = HandleAddressSpaceTypeAttribute(vDecl->getType(), + Attr); + // install the new addr spaced type into the decl + vDecl->setType(newType); + } + break; + case AttributeList::AT_deprecated: + HandleDeprecatedAttribute(New, Attr); + break; + case AttributeList::AT_visibility: + HandleVisibilityAttribute(New, Attr); + break; + case AttributeList::AT_weak: + HandleWeakAttribute(New, Attr); + break; + case AttributeList::AT_dllimport: + HandleDLLImportAttribute(New, Attr); + break; + case AttributeList::AT_dllexport: + HandleDLLExportAttribute(New, Attr); + break; + case AttributeList::AT_nothrow: + HandleNothrowAttribute(New, Attr); + break; + case AttributeList::AT_stdcall: + HandleStdCallAttribute(New, Attr); + break; + case AttributeList::AT_fastcall: + HandleFastCallAttribute(New, Attr); + break; + case AttributeList::AT_aligned: + HandleAlignedAttribute(New, Attr); + break; + case AttributeList::AT_packed: + HandlePackedAttribute(New, Attr); + break; + case AttributeList::AT_annotate: + HandleAnnotateAttribute(New, Attr); + break; + case AttributeList::AT_noreturn: + HandleNoReturnAttribute(New, Attr); + break; + case AttributeList::AT_format: + HandleFormatAttribute(New, Attr); + break; + default: +#if 0 + // TODO: when we have the full set of attributes, warn about unknown ones. + Diag(Attr->getLoc(), diag::warn_attribute_ignored, + Attr->getName()->getName()); +#endif + break; + } +} + +void Sema::HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix, + AttributeList *declarator_postfix) { + while (declspec_prefix) { + HandleDeclAttribute(New, declspec_prefix); + declspec_prefix = declspec_prefix->getNext(); + } + while (declarator_postfix) { + HandleDeclAttribute(New, declarator_postfix); + declarator_postfix = declarator_postfix->getNext(); + } +} + +void Sema::HandleOCUVectorTypeAttribute(TypedefDecl *tDecl, + AttributeList *rawAttr) { + QualType curType = tDecl->getUnderlyingType(); + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + Expr *sizeExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, + "ocu_vector_type", sizeExpr->getSourceRange()); + return; + } + // unlike gcc's vector_size attribute, we do not allow vectors to be defined + // in conjunction with complex types (pointers, arrays, functions, etc.). + Type *canonType = curType.getCanonicalType().getTypePtr(); + if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { + Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, + curType.getCanonicalType().getAsString()); + return; + } + // unlike gcc's vector_size attribute, the size is specified as the + // number of elements, not the number of bytes. + unsigned vectorSize = static_cast(vecSize.getZExtValue()); + + if (vectorSize == 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, + sizeExpr->getSourceRange()); + return; + } + // Instantiate/Install the vector type, the number of elements is > 0. + tDecl->setUnderlyingType(Context.getOCUVectorType(curType, vectorSize)); + // Remember this typedef decl, we will need it later for diagnostics. + OCUVectorDecls.push_back(tDecl); +} + +QualType Sema::HandleVectorTypeAttribute(QualType curType, + AttributeList *rawAttr) { + // check the attribute arugments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return QualType(); + } + Expr *sizeExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, + "vector_size", sizeExpr->getSourceRange()); + return QualType(); + } + // navigate to the base type - we need to provide for vector pointers, + // vector arrays, and functions returning vectors. + Type *canonType = curType.getCanonicalType().getTypePtr(); + + if (canonType->isPointerType() || canonType->isArrayType() || + canonType->isFunctionType()) { + assert(0 && "HandleVector(): Complex type construction unimplemented"); + /* FIXME: rebuild the type from the inside out, vectorizing the inner type. + do { + if (PointerType *PT = dyn_cast(canonType)) + canonType = PT->getPointeeType().getTypePtr(); + else if (ArrayType *AT = dyn_cast(canonType)) + canonType = AT->getElementType().getTypePtr(); + else if (FunctionType *FT = dyn_cast(canonType)) + canonType = FT->getResultType().getTypePtr(); + } while (canonType->isPointerType() || canonType->isArrayType() || + canonType->isFunctionType()); + */ + } + // the base type must be integer or float. + if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) { + Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type, + curType.getCanonicalType().getAsString()); + return QualType(); + } + unsigned typeSize = static_cast(Context.getTypeSize(curType)); + // vecSize is specified in bytes - convert to bits. + unsigned vectorSize = static_cast(vecSize.getZExtValue() * 8); + + // the vector size needs to be an integral multiple of the type size. + if (vectorSize % typeSize) { + Diag(rawAttr->getLoc(), diag::err_attribute_invalid_size, + sizeExpr->getSourceRange()); + return QualType(); + } + if (vectorSize == 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_zero_size, + sizeExpr->getSourceRange()); + return QualType(); + } + // Instantiate the vector type, the number of elements is > 0, and not + // required to be a power of 2, unlike GCC. + return Context.getVectorType(curType, vectorSize/typeSize); +} + +void Sema::HandlePackedAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() > 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + if (TagDecl *TD = dyn_cast(d)) + TD->addAttr(new PackedAttr); + else if (FieldDecl *FD = dyn_cast(d)) { + // If the alignment is less than or equal to 8 bits, the packed attribute + // has no effect. + if (Context.getTypeAlign(FD->getType()) <= 8) + Diag(rawAttr->getLoc(), + diag::warn_attribute_ignored_for_field_of_type, + rawAttr->getName()->getName(), FD->getType().getAsString()); + else + FD->addAttr(new PackedAttr); + } else + Diag(rawAttr->getLoc(), diag::warn_attribute_ignored, + rawAttr->getName()->getName()); +} + +void Sema::HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + FunctionDecl *Fn = dyn_cast(d); + + if (!Fn) { + Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, + "noreturn", "function"); + return; + } + + d->addAttr(new NoReturnAttr()); +} + +void Sema::HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new DeprecatedAttr()); +} + +void Sema::HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + + Expr *Arg = static_cast(rawAttr->getArg(0)); + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Str = dyn_cast(Arg); + + if (Str == 0 || Str->isWide()) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, + "visibility", std::string("1")); + return; + } + + const char *TypeStr = Str->getStrData(); + unsigned TypeLen = Str->getByteLength(); + llvm::GlobalValue::VisibilityTypes type; + + if (TypeLen == 7 && !memcmp(TypeStr, "default", 7)) + type = llvm::GlobalValue::DefaultVisibility; + else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6)) + type = llvm::GlobalValue::HiddenVisibility; + else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8)) + type = llvm::GlobalValue::HiddenVisibility; // FIXME + else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9)) + type = llvm::GlobalValue::ProtectedVisibility; + else { + Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, + "visibility", TypeStr); + return; + } + + d->addAttr(new VisibilityAttr(type)); +} + +void Sema::HandleWeakAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new WeakAttr()); +} + +void Sema::HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new DLLImportAttr()); +} + +void Sema::HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new DLLExportAttr()); +} + +void Sema::HandleStdCallAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new StdCallAttr()); +} + +void Sema::HandleFastCallAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new FastCallAttr()); +} + +void Sema::HandleNothrowAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 0) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return; + } + + d->addAttr(new NoThrowAttr()); +} + +/// Handle __attribute__((format(type,idx,firstarg))) attributes +/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) { + + if (!rawAttr->getParameterName()) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string, + "format", std::string("1")); + return; + } + + if (rawAttr->getNumArgs() != 2) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("3")); + return; + } + + FunctionDecl *Fn = dyn_cast(d); + if (!Fn) { + Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type, + "format", "function"); + return; + } + + const FunctionTypeProto *proto = + dyn_cast(Fn->getType()->getAsFunctionType()); + if (!proto) + return; + + // FIXME: in C++ the implicit 'this' function parameter also counts. + // this is needed in order to be compatible with GCC + // the index must start in 1 and the limit is numargs+1 + unsigned NumArgs = Fn->getNumParams(); + unsigned FirstIdx = 1; + + const char *Format = rawAttr->getParameterName()->getName(); + unsigned FormatLen = rawAttr->getParameterName()->getLength(); + + // Normalize the argument, __foo__ becomes foo. + if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && + Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { + Format += 2; + FormatLen -= 4; + } + + if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5)) + || (FormatLen == 6 && !memcmp(Format, "printf", 6)) + || (FormatLen == 7 && !memcmp(Format, "strfmon", 7)) + || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) { + Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, + "format", rawAttr->getParameterName()->getName()); + return; + } + + // checks for the 2nd argument + Expr *IdxExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt Idx(Context.getTypeSize(IdxExpr->getType())); + if (!IdxExpr->isIntegerConstantExpr(Idx, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, + "format", std::string("2"), IdxExpr->getSourceRange()); + return; + } + + if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, + "format", std::string("2"), IdxExpr->getSourceRange()); + return; + } + + // make sure the format string is really a string + QualType Ty = proto->getArgType(Idx.getZExtValue()-1); + if (!Ty->isPointerType() || + !Ty->getAsPointerType()->getPointeeType()->isCharType()) { + Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string, + IdxExpr->getSourceRange()); + return; + } + + + // check the 3rd argument + Expr *FirstArgExpr = static_cast(rawAttr->getArg(1)); + llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType())); + if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int, + "format", std::string("3"), FirstArgExpr->getSourceRange()); + return; + } + + // check if the function is variadic if the 3rd argument non-zero + if (FirstArg != 0) { + if (proto->isVariadic()) { + ++NumArgs; // +1 for ... + } else { + Diag(d->getLocation(), diag::err_format_attribute_requires_variadic); + return; + } + } + + // strftime requires FirstArg to be 0 because it doesn't read from any variable + // the input is just the current time + the format string + if (FormatLen == 8 && !memcmp(Format, "strftime", 8)) { + if (FirstArg != 0) { + Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter, + FirstArgExpr->getSourceRange()); + return; + } + // if 0 it disables parameter checking (to use with e.g. va_list) + } else if (FirstArg != 0 && FirstArg != NumArgs) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds, + "format", std::string("3"), FirstArgExpr->getSourceRange()); + return; + } + + d->addAttr(new FormatAttr(std::string(Format, FormatLen), + Idx.getZExtValue(), FirstArg.getZExtValue())); +} + +void Sema::HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr) { + // check the attribute arguments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + Expr *argExpr = static_cast(rawAttr->getArg(0)); + StringLiteral *SE = dyn_cast(argExpr); + + // Make sure that there is a string literal as the annotation's single + // argument. + if (!SE) { + Diag(rawAttr->getLoc(), diag::err_attribute_annotate_no_string); + return; + } + d->addAttr(new AnnotateAttr(std::string(SE->getStrData(), + SE->getByteLength()))); +} + +void Sema::HandleAlignedAttribute(Decl *d, AttributeList *rawAttr) +{ + // check the attribute arguments. + if (rawAttr->getNumArgs() > 1) { + Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return; + } + + unsigned Align = 0; + + if (rawAttr->getNumArgs() == 0) { + // FIXME: This should be the target specific maximum alignment. + // (For now we just use 128 bits which is the maximum on X86. + Align = 128; + return; + } else { + Expr *alignmentExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt alignment(32); + if (!alignmentExpr->isIntegerConstantExpr(alignment, Context)) { + Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int, + "aligned", alignmentExpr->getSourceRange()); + return; + } + + Align = alignment.getZExtValue() * 8; + } + + d->addAttr(new AlignedAttr(Align)); +} diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp new file mode 100644 index 00000000000..20d127b31eb --- /dev/null +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -0,0 +1,927 @@ +//===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective C declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Parse/Scope.h" + +using namespace clang; + +/// ObjCActOnStartOfMethodDef - This routine sets up parameters; invisible +/// and user declared, in the method definition's AST. +void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { + assert(CurFunctionDecl == 0 && "Method parsing confused"); + ObjCMethodDecl *MDecl = dyn_cast(static_cast(D)); + assert(MDecl != 0 && "Not a method declarator!"); + + // Allow the rest of sema to find private method decl implementations. + if (MDecl->isInstance()) + AddInstanceMethodToGlobalPool(MDecl); + else + AddFactoryMethodToGlobalPool(MDecl); + + // Allow all of Sema to see that we are entering a method definition. + CurMethodDecl = MDecl; + + // Create Decl objects for each parameter, entrring them in the scope for + // binding to their use. + struct DeclaratorChunk::ParamInfo PI; + + // Insert the invisible arguments, self and _cmd! + PI.Ident = &Context.Idents.get("self"); + PI.IdentLoc = SourceLocation(); // synthesized vars have a null location. + PI.InvalidType = false; + PI.AttrList = 0; + PI.TypeInfo = Context.getObjCIdType().getAsOpaquePtr(); + + if (MDecl->isInstance()) { + if (ObjCInterfaceDecl *OID = MDecl->getClassInterface()) { + // There may be no interface context due to error in declaration of the + // interface (which has been reported). Recover gracefully + QualType selfTy = Context.getObjCInterfaceType(OID); + selfTy = Context.getPointerType(selfTy); + PI.TypeInfo = selfTy.getAsOpaquePtr(); + } + } + + CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope)); + + PI.Ident = &Context.Idents.get("_cmd"); + PI.TypeInfo = Context.getObjCSelType().getAsOpaquePtr(); + ActOnParamDeclarator(PI, FnBodyScope); + + for (int i = 0; i < MDecl->getNumParams(); i++) { + ParmVarDecl *PDecl = MDecl->getParamDecl(i); + PI.Ident = PDecl->getIdentifier(); + PI.IdentLoc = PDecl->getLocation(); // user vars have a real location. + PI.TypeInfo = PDecl->getType().getAsOpaquePtr(); + MDecl->setParamDecl(i, ActOnParamDeclarator(PI, FnBodyScope)); + } +} + +Sema::DeclTy *Sema::ActOnStartClassInterface( + SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + IdentifierInfo **ProtocolNames, unsigned NumProtocols, + SourceLocation EndProtoLoc, AttributeList *AttrList) { + assert(ClassName && "Missing class identifier"); + + // Check for another declaration kind with the same name. + ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); + if (PrevDecl && !isa(PrevDecl)) { + Diag(ClassLoc, diag::err_redefinition_different_kind, + ClassName->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + + ObjCInterfaceDecl* IDecl = dyn_cast_or_null(PrevDecl); + if (IDecl) { + // Class already seen. Is it a forward declaration? + if (!IDecl->isForwardDecl()) + Diag(AtInterfaceLoc, diag::err_duplicate_class_def, IDecl->getName()); + else { + IDecl->setLocation(AtInterfaceLoc); + IDecl->setForwardDecl(false); + IDecl->AllocIntfRefProtocols(NumProtocols); + } + } + else { + IDecl = new ObjCInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName); + + // Chain & install the interface decl into the identifier. + IDecl->setNext(ClassName->getFETokenInfo()); + ClassName->setFETokenInfo(IDecl); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IDecl); + } + + if (SuperName) { + ObjCInterfaceDecl* SuperClassEntry = 0; + // Check if a different kind of symbol declared in this scope. + PrevDecl = LookupInterfaceDecl(SuperName); + if (PrevDecl && !isa(PrevDecl)) { + Diag(SuperLoc, diag::err_redefinition_different_kind, + SuperName->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + else { + // Check that super class is previously defined + SuperClassEntry = dyn_cast_or_null(PrevDecl); + + if (!SuperClassEntry || SuperClassEntry->isForwardDecl()) { + Diag(AtInterfaceLoc, diag::err_undef_superclass, + SuperClassEntry ? SuperClassEntry->getName() + : SuperName->getName(), + ClassName->getName()); + } + } + IDecl->setSuperClass(SuperClassEntry); + IDecl->setLocEnd(SuperLoc); + } else { // we have a root class. + IDecl->setLocEnd(ClassLoc); + } + + /// Check then save referenced protocols + if (NumProtocols) { + for (unsigned int i = 0; i != NumProtocols; i++) { + ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtocolNames[i]]; + if (!RefPDecl || RefPDecl->isForwardDecl()) + Diag(ClassLoc, diag::warn_undef_protocolref, + ProtocolNames[i]->getName(), + ClassName->getName()); + IDecl->setIntfRefProtocols(i, RefPDecl); + } + IDecl->setLocEnd(EndProtoLoc); + } + return IDecl; +} + +/// ActOnCompatiblityAlias - this action is called after complete parsing of +/// @compaatibility_alias declaration. It sets up the alias relationships. +Sema::DeclTy *Sema::ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation) { + // Look for previous declaration of alias name + ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary, + AliasLocation, TUScope); + if (ADecl) { + if (isa(ADecl)) { + Diag(AliasLocation, diag::warn_previous_alias_decl); + Diag(ADecl->getLocation(), diag::warn_previous_declaration); + } + else { + Diag(AliasLocation, diag::err_conflicting_aliasing_type, + AliasName->getName()); + Diag(ADecl->getLocation(), diag::err_previous_declaration); + } + return 0; + } + // Check for class declaration + ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary, + ClassLocation, TUScope); + if (!CDecl || !isa(CDecl)) { + Diag(ClassLocation, diag::warn_undef_interface, + ClassName->getName()); + if (CDecl) + Diag(CDecl->getLocation(), diag::warn_previous_declaration); + return 0; + } + // Everything checked out, instantiate a new alias declaration ast + ObjCCompatibleAliasDecl *AliasDecl = + new ObjCCompatibleAliasDecl(AtCompatibilityAliasLoc, + AliasName, + dyn_cast(CDecl)); + + // Chain & install the interface decl into the identifier. + AliasDecl->setNext(AliasName->getFETokenInfo()); + AliasName->setFETokenInfo(AliasDecl); + return AliasDecl; +} + +Sema::DeclTy *Sema::ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, + IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc) { + assert(ProtocolName && "Missing protocol identifier"); + ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolName]; + if (PDecl) { + // Protocol already seen. Better be a forward protocol declaration + if (!PDecl->isForwardDecl()) + Diag(ProtocolLoc, diag::err_duplicate_protocol_def, + ProtocolName->getName()); + else { + PDecl->setForwardDecl(false); + PDecl->AllocReferencedProtocols(NumProtoRefs); + } + } + else { + PDecl = new ObjCProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs, + ProtocolName); + ObjCProtocols[ProtocolName] = PDecl; + } + + if (NumProtoRefs) { + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtoRefs; i++) { + ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtoRefNames[i]]; + if (!RefPDecl || RefPDecl->isForwardDecl()) + Diag(ProtocolLoc, diag::warn_undef_protocolref, + ProtoRefNames[i]->getName(), + ProtocolName->getName()); + PDecl->setReferencedProtocols(i, RefPDecl); + } + PDecl->setLocEnd(EndProtoLoc); + } + return PDecl; +} + +/// FindProtocolDeclaration - This routine looks up protocols and +/// issuer error if they are not declared. It returns list of protocol +/// declarations in its 'Protocols' argument. +void +Sema::FindProtocolDeclaration(SourceLocation TypeLoc, + IdentifierInfo **ProtocolId, + unsigned NumProtocols, + llvm::SmallVector &Protocols) { + for (unsigned i = 0; i != NumProtocols; ++i) { + ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolId[i]]; + if (!PDecl) + Diag(TypeLoc, diag::err_undeclared_protocol, + ProtocolId[i]->getName()); + else + Protocols.push_back(PDecl); + } +} + +/// ActOnForwardProtocolDeclaration - +Action::DeclTy * +Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, + IdentifierInfo **IdentList, unsigned NumElts) { + llvm::SmallVector Protocols; + + for (unsigned i = 0; i != NumElts; ++i) { + IdentifierInfo *P = IdentList[i]; + ObjCProtocolDecl *PDecl = ObjCProtocols[P]; + if (!PDecl) { // Not already seen? + // FIXME: Pass in the location of the identifier! + PDecl = new ObjCProtocolDecl(AtProtocolLoc, 0, P, true); + ObjCProtocols[P] = PDecl; + } + + Protocols.push_back(PDecl); + } + return new ObjCForwardProtocolDecl(AtProtocolLoc, + &Protocols[0], Protocols.size()); +} + +Sema::DeclTy *Sema::ActOnStartCategoryInterface( + SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc) { + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + + ObjCCategoryDecl *CDecl = new ObjCCategoryDecl(AtInterfaceLoc, NumProtoRefs, + CategoryName); + CDecl->setClassInterface(IDecl); + + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) + Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); + else { + /// Check for duplicate interface declaration for this category + ObjCCategoryDecl *CDeclChain; + for (CDeclChain = IDecl->getCategoryList(); CDeclChain; + CDeclChain = CDeclChain->getNextClassCategory()) { + if (CDeclChain->getIdentifier() == CategoryName) { + Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(), + CategoryName->getName()); + break; + } + } + if (!CDeclChain) + CDecl->insertNextClassCategory(); + } + + if (NumProtoRefs) { + /// Check then save referenced protocols + for (unsigned int i = 0; i != NumProtoRefs; i++) { + ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtoRefNames[i]]; + if (!RefPDecl || RefPDecl->isForwardDecl()) { + Diag(CategoryLoc, diag::warn_undef_protocolref, + ProtoRefNames[i]->getName(), + CategoryName->getName()); + } + CDecl->setCatReferencedProtocols(i, RefPDecl); + } + CDecl->setLocEnd(EndProtoLoc); + } + return CDecl; +} + +/// ActOnStartCategoryImplementation - Perform semantic checks on the +/// category implementation declaration and build an ObjCCategoryImplDecl +/// object. +Sema::DeclTy *Sema::ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CatName, SourceLocation CatLoc) { + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCCategoryImplDecl *CDecl = new ObjCCategoryImplDecl(AtCatImplLoc, + CatName, IDecl); + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) + Diag(ClassLoc, diag::err_undef_interface, ClassName->getName()); + + /// TODO: Check that CatName, category name, is not used in another + // implementation. + return CDecl; +} + +Sema::DeclTy *Sema::ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc) { + ObjCInterfaceDecl* IDecl = 0; + // Check for another declaration kind with the same name. + ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName); + if (PrevDecl && !isa(PrevDecl)) { + Diag(ClassLoc, diag::err_redefinition_different_kind, + ClassName->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + else { + // Is there an interface declaration of this class; if not, warn! + IDecl = dyn_cast_or_null(PrevDecl); + if (!IDecl) + Diag(ClassLoc, diag::warn_undef_interface, ClassName->getName()); + } + + // Check that super class name is valid class name + ObjCInterfaceDecl* SDecl = 0; + if (SuperClassname) { + // Check if a different kind of symbol declared in this scope. + PrevDecl = LookupInterfaceDecl(SuperClassname); + if (PrevDecl && !isa(PrevDecl)) { + Diag(SuperClassLoc, diag::err_redefinition_different_kind, + SuperClassname->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + else { + SDecl = dyn_cast_or_null(PrevDecl); + if (!SDecl) + Diag(SuperClassLoc, diag::err_undef_superclass, + SuperClassname->getName(), ClassName->getName()); + else if (IDecl && IDecl->getSuperClass() != SDecl) { + // This implementation and its interface do not have the same + // super class. + Diag(SuperClassLoc, diag::err_conflicting_super_class, + SDecl->getName()); + Diag(SDecl->getLocation(), diag::err_previous_definition); + } + } + } + + if (!IDecl) { + // Legacy case of @implementation with no corresponding @interface. + // Build, chain & install the interface decl into the identifier. + IDecl = new ObjCInterfaceDecl(AtClassImplLoc, 0, ClassName, + false, true); + IDecl->setNext(ClassName->getFETokenInfo()); + ClassName->setFETokenInfo(IDecl); + IDecl->setSuperClass(SDecl); + IDecl->setLocEnd(ClassLoc); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IDecl); + } + + ObjCImplementationDecl* IMPDecl = + new ObjCImplementationDecl(AtClassImplLoc, ClassName, IDecl, SDecl); + + // Check that there is no duplicate implementation of this class. + if (ObjCImplementations[ClassName]) + Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName()); + else // add it to the list. + ObjCImplementations[ClassName] = IMPDecl; + return IMPDecl; +} + +void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **ivars, unsigned numIvars, + SourceLocation RBrace) { + assert(ImpDecl && "missing implementation decl"); + ObjCInterfaceDecl* IDecl = getObjCInterfaceDecl(ImpDecl->getIdentifier()); + if (!IDecl) + return; + /// Check case of non-existing @interface decl. + /// (legacy objective-c @implementation decl without an @interface decl). + /// Add implementations's ivar to the synthesize class's ivar list. + if (IDecl->ImplicitInterfaceDecl()) { + IDecl->addInstanceVariablesToClass(ivars, numIvars, RBrace); + return; + } + // If implementation has empty ivar list, just return. + if (numIvars == 0) + return; + + assert(ivars && "missing @implementation ivars"); + + // Check interface's Ivar list against those in the implementation. + // names and types must match. + // + unsigned j = 0; + ObjCInterfaceDecl::ivar_iterator + IVI = IDecl->ivar_begin(), IVE = IDecl->ivar_end(); + for (; numIvars > 0 && IVI != IVE; ++IVI) { + ObjCIvarDecl* ImplIvar = ivars[j++]; + ObjCIvarDecl* ClsIvar = *IVI; + assert (ImplIvar && "missing implementation ivar"); + assert (ClsIvar && "missing class ivar"); + if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) { + Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type, + ImplIvar->getIdentifier()->getName()); + Diag(ClsIvar->getLocation(), diag::err_previous_definition, + ClsIvar->getIdentifier()->getName()); + } + // TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed + // as error. + else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { + Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name, + ImplIvar->getIdentifier()->getName()); + Diag(ClsIvar->getLocation(), diag::err_previous_definition, + ClsIvar->getIdentifier()->getName()); + return; + } + --numIvars; + } + + if (numIvars > 0) + Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count); + else if (IVI != IVE) + Diag((*IVI)->getLocation(), diag::err_inconsistant_ivar_count); +} + +void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, + bool &IncompleteImpl) { + if (!IncompleteImpl) { + Diag(ImpLoc, diag::warn_incomplete_impl); + IncompleteImpl = true; + } + Diag(ImpLoc, diag::warn_undef_method_impl, method->getSelector().getName()); +} + +/// CheckProtocolMethodDefs - This routine checks unimplemented methods +/// Declared in protocol, and those referenced by it. +void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, + ObjCProtocolDecl *PDecl, + bool& IncompleteImpl, + const llvm::DenseSet &InsMap, + const llvm::DenseSet &ClsMap) { + // check unimplemented instance methods. + for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), + E = PDecl->instmeth_end(); I != E; ++I) { + ObjCMethodDecl *method = *I; + if (!InsMap.count(method->getSelector()) && + method->getImplementationControl() != ObjCMethodDecl::Optional) + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + } + // check unimplemented class methods + for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), + E = PDecl->classmeth_end(); I != E; ++I) { + ObjCMethodDecl *method = *I; + if (!ClsMap.count(method->getSelector()) && + method->getImplementationControl() != ObjCMethodDecl::Optional) + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + } + // Check on this protocols's referenced protocols, recursively + ObjCProtocolDecl** RefPDecl = PDecl->getReferencedProtocols(); + for (unsigned i = 0; i < PDecl->getNumReferencedProtocols(); i++) + CheckProtocolMethodDefs(ImpLoc, RefPDecl[i], IncompleteImpl, InsMap, ClsMap); +} + +void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, + ObjCInterfaceDecl* IDecl) { + llvm::DenseSet InsMap; + // Check and see if instance methods in class interface have been + // implemented in the implementation class. + for (ObjCImplementationDecl::instmeth_iterator I = IMPDecl->instmeth_begin(), + E = IMPDecl->instmeth_end(); I != E; ++I) + InsMap.insert((*I)->getSelector()); + + bool IncompleteImpl = false; + for (ObjCInterfaceDecl::instmeth_iterator I = IDecl->instmeth_begin(), + E = IDecl->instmeth_end(); I != E; ++I) + if (!InsMap.count((*I)->getSelector())) + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + + llvm::DenseSet ClsMap; + // Check and see if class methods in class interface have been + // implemented in the implementation class. + for (ObjCImplementationDecl::classmeth_iterator I =IMPDecl->classmeth_begin(), + E = IMPDecl->classmeth_end(); I != E; ++I) + ClsMap.insert((*I)->getSelector()); + + for (ObjCInterfaceDecl::classmeth_iterator I = IDecl->classmeth_begin(), + E = IDecl->classmeth_end(); I != E; ++I) + if (!ClsMap.count((*I)->getSelector())) + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + + // Check the protocol list for unimplemented methods in the @implementation + // class. + ObjCProtocolDecl** protocols = IDecl->getReferencedProtocols(); + for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) + CheckProtocolMethodDefs(IMPDecl->getLocation(), protocols[i], + IncompleteImpl, InsMap, ClsMap); +} + +/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the +/// category interface is implemented in the category @implementation. +void Sema::ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl, + ObjCCategoryDecl *CatClassDecl) { + llvm::DenseSet InsMap; + // Check and see if instance methods in category interface have been + // implemented in its implementation class. + for (ObjCCategoryImplDecl::instmeth_iterator I =CatImplDecl->instmeth_begin(), + E = CatImplDecl->instmeth_end(); I != E; ++I) + InsMap.insert((*I)->getSelector()); + + bool IncompleteImpl = false; + for (ObjCCategoryDecl::instmeth_iterator I = CatClassDecl->instmeth_begin(), + E = CatClassDecl->instmeth_end(); I != E; ++I) + if (!InsMap.count((*I)->getSelector())) + WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl); + + llvm::DenseSet ClsMap; + // Check and see if class methods in category interface have been + // implemented in its implementation class. + for (ObjCCategoryImplDecl::classmeth_iterator + I = CatImplDecl->classmeth_begin(), E = CatImplDecl->classmeth_end(); + I != E; ++I) + ClsMap.insert((*I)->getSelector()); + + for (ObjCCategoryDecl::classmeth_iterator I = CatClassDecl->classmeth_begin(), + E = CatClassDecl->classmeth_end(); I != E; ++I) + if (!ClsMap.count((*I)->getSelector())) + WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl); + + // Check the protocol list for unimplemented methods in the @implementation + // class. + ObjCProtocolDecl** protocols = CatClassDecl->getReferencedProtocols(); + for (unsigned i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) { + ObjCProtocolDecl* PDecl = protocols[i]; + CheckProtocolMethodDefs(CatImplDecl->getLocation(), PDecl, IncompleteImpl, + InsMap, ClsMap); + } +} + +/// ActOnForwardClassDeclaration - +Action::DeclTy * +Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, + IdentifierInfo **IdentList, unsigned NumElts) +{ + llvm::SmallVector Interfaces; + + for (unsigned i = 0; i != NumElts; ++i) { + // Check for another declaration kind with the same name. + ScopedDecl *PrevDecl = LookupInterfaceDecl(IdentList[i]); + if (PrevDecl && !isa(PrevDecl)) { + Diag(AtClassLoc, diag::err_redefinition_different_kind, + IdentList[i]->getName()); + Diag(PrevDecl->getLocation(), diag::err_previous_definition); + } + ObjCInterfaceDecl *IDecl = dyn_cast_or_null(PrevDecl); + if (!IDecl) { // Not already seen? Make a forward decl. + IDecl = new ObjCInterfaceDecl(AtClassLoc, 0, IdentList[i], true); + // Chain & install the interface decl into the identifier. + IDecl->setNext(IdentList[i]->getFETokenInfo()); + IdentList[i]->setFETokenInfo(IDecl); + + // Remember that this needs to be removed when the scope is popped. + TUScope->AddDecl(IDecl); + } + + Interfaces.push_back(IDecl); + } + + return new ObjCClassDecl(AtClassLoc, &Interfaces[0], Interfaces.size()); +} + + +/// MatchTwoMethodDeclarations - Checks that two methods have matching type and +/// returns true, or false, accordingly. +/// TODO: Handle protocol list; such as id in type comparisons +bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod) { + if (Method->getResultType().getCanonicalType() != + PrevMethod->getResultType().getCanonicalType()) + return false; + for (int i = 0; i < Method->getNumParams(); i++) { + ParmVarDecl *ParamDecl = Method->getParamDecl(i); + ParmVarDecl *PrevParamDecl = PrevMethod->getParamDecl(i); + if (ParamDecl->getCanonicalType() != PrevParamDecl->getCanonicalType()) + return false; + } + return true; +} + +void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { + ObjCMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()]; + if (!FirstMethod.Method) { + // Haven't seen a method with this selector name yet - add it. + FirstMethod.Method = Method; + FirstMethod.Next = 0; + } else { + // We've seen a method with this name, now check the type signature(s). + bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); + + for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; + Next = Next->Next) + match = MatchTwoMethodDeclarations(Method, Next->Method); + + if (!match) { + // We have a new signature for an existing method - add it. + // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". + struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next); + FirstMethod.Next = OMI; + } + } +} + +void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { + ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()]; + if (!FirstMethod.Method) { + // Haven't seen a method with this selector name yet - add it. + FirstMethod.Method = Method; + FirstMethod.Next = 0; + } else { + // We've seen a method with this name, now check the type signature(s). + bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); + + for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; + Next = Next->Next) + match = MatchTwoMethodDeclarations(Method, Next->Method); + + if (!match) { + // We have a new signature for an existing method - add it. + // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". + struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next); + FirstMethod.Next = OMI; + } + } +} + +// Note: For class/category implemenations, allMethods/allProperties is +// always null. +void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, + DeclTy **allMethods, unsigned allNum, + DeclTy **allProperties, unsigned pNum) { + Decl *ClassDecl = static_cast(classDecl); + + // FIXME: If we don't have a ClassDecl, we have an error. We should consider + // always passing in a decl. If the decl has an error, isInvalidDecl() + // should be true. + if (!ClassDecl) + return; + + llvm::SmallVector insMethods; + llvm::SmallVector clsMethods; + + llvm::DenseMap InsMap; + llvm::DenseMap ClsMap; + + bool isInterfaceDeclKind = + (isa(ClassDecl) || isa(ClassDecl) + || isa(ClassDecl)); + bool checkIdenticalMethods = isa(ClassDecl); + + // TODO: property declaration in category and protocols. + if (pNum != 0 && isa(ClassDecl)) { + ObjCPropertyDecl **properties = new ObjCPropertyDecl*[pNum]; + memcpy(properties, allProperties, pNum*sizeof(ObjCPropertyDecl*)); + dyn_cast(ClassDecl)->setPropertyDecls(properties); + dyn_cast(ClassDecl)->setNumPropertyDecl(pNum); + } + + for (unsigned i = 0; i < allNum; i++ ) { + ObjCMethodDecl *Method = + cast_or_null(static_cast(allMethods[i])); + + if (!Method) continue; // Already issued a diagnostic. + if (Method->isInstance()) { + /// Check for instance method of the same name with incompatible types + const ObjCMethodDecl *&PrevMethod = InsMap[Method->getSelector()]; + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + : false; + if (isInterfaceDeclKind && PrevMethod && !match + || checkIdenticalMethods && match) { + Diag(Method->getLocation(), diag::error_duplicate_method_decl, + Method->getSelector().getName()); + Diag(PrevMethod->getLocation(), diag::err_previous_declaration); + } else { + insMethods.push_back(Method); + InsMap[Method->getSelector()] = Method; + /// The following allows us to typecheck messages to "id". + AddInstanceMethodToGlobalPool(Method); + } + } + else { + /// Check for class method of the same name with incompatible types + const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()]; + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + : false; + if (isInterfaceDeclKind && PrevMethod && !match + || checkIdenticalMethods && match) { + Diag(Method->getLocation(), diag::error_duplicate_method_decl, + Method->getSelector().getName()); + Diag(PrevMethod->getLocation(), diag::err_previous_declaration); + } else { + clsMethods.push_back(Method); + ClsMap[Method->getSelector()] = Method; + /// The following allows us to typecheck messages to "Class". + AddFactoryMethodToGlobalPool(Method); + } + } + } + + if (ObjCInterfaceDecl *I = dyn_cast(ClassDecl)) { + I->addMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size(), AtEndLoc); + } else if (ObjCProtocolDecl *P = dyn_cast(ClassDecl)) { + P->addMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size(), AtEndLoc); + } + else if (ObjCCategoryDecl *C = dyn_cast(ClassDecl)) { + C->addMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size(), AtEndLoc); + } + else if (ObjCImplementationDecl *IC = + dyn_cast(ClassDecl)) { + IC->setLocEnd(AtEndLoc); + if (ObjCInterfaceDecl* IDecl = getObjCInterfaceDecl(IC->getIdentifier())) + ImplMethodsVsClassMethods(IC, IDecl); + } else { + ObjCCategoryImplDecl* CatImplClass = cast(ClassDecl); + CatImplClass->setLocEnd(AtEndLoc); + ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface(); + // Find category interface decl and then check that all methods declared + // in this interface is implemented in the category @implementation. + if (IDecl) { + for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); + Categories; Categories = Categories->getNextClassCategory()) { + if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { + ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories); + break; + } + } + } + } +} + + +/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for +/// objective-c's type qualifier from the parser version of the same info. +static Decl::ObjCDeclQualifier +CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { + Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None; + if (PQTVal & ObjCDeclSpec::DQ_In) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_In); + if (PQTVal & ObjCDeclSpec::DQ_Inout) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Inout); + if (PQTVal & ObjCDeclSpec::DQ_Out) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Out); + if (PQTVal & ObjCDeclSpec::DQ_Bycopy) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy); + if (PQTVal & ObjCDeclSpec::DQ_Byref) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Byref); + if (PQTVal & ObjCDeclSpec::DQ_Oneway) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Oneway); + + return ret; +} + +Sema::DeclTy *Sema::ActOnMethodDeclaration( + SourceLocation MethodLoc, SourceLocation EndLoc, + tok::TokenKind MethodType, DeclTy *ClassDecl, + ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, + Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames, + AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, + bool isVariadic) { + + // Make sure we can establish a context for the method. + if (!ClassDecl) { + Diag(MethodLoc, diag::error_missing_method_context); + return 0; + } + llvm::SmallVector Params; + + for (unsigned i = 0; i < Sel.getNumArgs(); i++) { + // FIXME: arg->AttrList must be stored too! + QualType argType; + + if (ArgTypes[i]) + argType = QualType::getFromOpaquePtr(ArgTypes[i]); + else + argType = Context.getObjCIdType(); + ParmVarDecl* Param = ParmVarDecl::Create(Context, SourceLocation(/*FIXME*/), + ArgNames[i], argType, + VarDecl::None, 0); + Param->setObjCDeclQualifier( + CvtQTToAstBitMask(ArgQT[i].getObjCDeclQualifier())); + Params.push_back(Param); + } + QualType resultDeclType; + + if (ReturnType) + resultDeclType = QualType::getFromOpaquePtr(ReturnType); + else // get the type for "id". + resultDeclType = Context.getObjCIdType(); + + Decl *CDecl = static_cast(ClassDecl); + ObjCMethodDecl* ObjCMethod = new ObjCMethodDecl(MethodLoc, EndLoc, Sel, + resultDeclType, + CDecl, + 0, -1, AttrList, + MethodType == tok::minus, isVariadic, + MethodDeclKind == tok::objc_optional ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + ObjCMethod->setMethodParams(&Params[0], Sel.getNumArgs()); + ObjCMethod->setObjCDeclQualifier( + CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); + const ObjCMethodDecl *PrevMethod = 0; + + // For implementations (which can be very "coarse grain"), we add the + // method now. This allows the AST to implement lookup methods that work + // incrementally (without waiting until we parse the @end). It also allows + // us to flag multiple declaration errors as they occur. + if (ObjCImplementationDecl *ImpDecl = + dyn_cast(CDecl)) { + if (MethodType == tok::minus) { + PrevMethod = ImpDecl->getInstanceMethod(Sel); + ImpDecl->addInstanceMethod(ObjCMethod); + } else { + PrevMethod = ImpDecl->getClassMethod(Sel); + ImpDecl->addClassMethod(ObjCMethod); + } + } + else if (ObjCCategoryImplDecl *CatImpDecl = + dyn_cast(CDecl)) { + if (MethodType == tok::minus) { + PrevMethod = CatImpDecl->getInstanceMethod(Sel); + CatImpDecl->addInstanceMethod(ObjCMethod); + } else { + PrevMethod = CatImpDecl->getClassMethod(Sel); + CatImpDecl->addClassMethod(ObjCMethod); + } + } + if (PrevMethod) { + // You can never have two method definitions with the same name. + Diag(ObjCMethod->getLocation(), diag::error_duplicate_method_decl, + ObjCMethod->getSelector().getName()); + Diag(PrevMethod->getLocation(), diag::err_previous_declaration); + } + return ObjCMethod; +} + +Sema::DeclTy *Sema::ActOnAddObjCProperties(SourceLocation AtLoc, + DeclTy **allProperties, unsigned NumProperties, ObjCDeclSpec &DS) { + ObjCPropertyDecl *PDecl = new ObjCPropertyDecl(AtLoc); + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_getter) { + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); + PDecl->setGetterName(DS.getGetterName()); + } + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_setter) { + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); + PDecl->setSetterName(DS.getSetterName()); + } + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_assign) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readwrite) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_retain) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_copy) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + + if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + + PDecl->setNumPropertyDecls(NumProperties); + if (NumProperties != 0) { + ObjCIvarDecl **properties = new ObjCIvarDecl*[NumProperties]; + memcpy(properties, allProperties, NumProperties*sizeof(ObjCIvarDecl*)); + PDecl->setPropertyDecls(properties); + } + return PDecl; +} + diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp new file mode 100644 index 00000000000..d756345c1a8 --- /dev/null +++ b/clang/lib/Sema/SemaExpr.cpp @@ -0,0 +1,2286 @@ +//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for expressions. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "SemaUtil.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; + +/// ActOnStringLiteral - The specified tokens were lexed as pasted string +/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string +/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from +/// multiple tokens. However, the common case is that StringToks points to one +/// string. +/// +Action::ExprResult +Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { + assert(NumStringToks && "Must have at least one string!"); + + StringLiteralParser Literal(StringToks, NumStringToks, PP, Context.Target); + if (Literal.hadError) + return ExprResult(true); + + llvm::SmallVector StringTokLocs; + for (unsigned i = 0; i != NumStringToks; ++i) + StringTokLocs.push_back(StringToks[i].getLocation()); + + // Verify that pascal strings aren't too large. + if (Literal.Pascal && Literal.GetStringLength() > 256) + return Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long, + SourceRange(StringToks[0].getLocation(), + StringToks[NumStringToks-1].getLocation())); + + QualType StrTy = Context.CharTy; + // FIXME: handle wchar_t + if (Literal.Pascal) StrTy = Context.UnsignedCharTy; + + // Get an array type for the string, according to C99 6.4.5. This includes + // the nul terminator character as well as the string length for pascal + // strings. + StrTy = Context.getConstantArrayType(StrTy, + llvm::APInt(32, Literal.GetStringLength()+1), + ArrayType::Normal, 0); + + // Pass &StringTokLocs[0], StringTokLocs.size() to factory! + return new StringLiteral(Literal.GetString(), Literal.GetStringLength(), + Literal.AnyWide, StrTy, + StringToks[0].getLocation(), + StringToks[NumStringToks-1].getLocation()); +} + + +/// ActOnIdentifierExpr - The parser read an identifier in expression context, +/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this +/// identifier is used in an function call context. +Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, + IdentifierInfo &II, + bool HasTrailingLParen) { + // Could be enum-constant or decl. + ScopedDecl *D = LookupScopedDecl(&II, Decl::IDNS_Ordinary, Loc, S); + if (D == 0) { + // Otherwise, this could be an implicitly declared function reference (legal + // in C90, extension in C99). + if (HasTrailingLParen && + // Not in C++. + !getLangOptions().CPlusPlus) + D = ImplicitlyDefineFunction(Loc, II, S); + else { + if (CurMethodDecl) { + ObjCInterfaceDecl *IFace = CurMethodDecl->getClassInterface(); + ObjCInterfaceDecl *clsDeclared; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&II, clsDeclared)) { + IdentifierInfo &II = Context.Idents.get("self"); + ExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false); + return new ObjCIvarRefExpr(IV, IV->getType(), Loc, + static_cast(SelfExpr.Val), true, true); + } + } + // If this name wasn't predeclared and if this is not a function call, + // diagnose the problem. + return Diag(Loc, diag::err_undeclared_var_use, II.getName()); + } + } + if (ValueDecl *VD = dyn_cast(D)) { + // check if referencing an identifier with __attribute__((deprecated)). + if (VD->getAttr()) + Diag(Loc, diag::warn_deprecated, VD->getName()); + + // Only create DeclRefExpr's for valid Decl's. + if (VD->isInvalidDecl()) + return true; + return new DeclRefExpr(VD, VD->getType(), Loc); + } + if (isa(D)) + return Diag(Loc, diag::err_unexpected_typedef, II.getName()); + if (isa(D)) + return Diag(Loc, diag::err_unexpected_interface, II.getName()); + + assert(0 && "Invalid decl"); + abort(); +} + +Sema::ExprResult Sema::ActOnPreDefinedExpr(SourceLocation Loc, + tok::TokenKind Kind) { + PreDefinedExpr::IdentType IT; + + switch (Kind) { + default: assert(0 && "Unknown simple primary expr!"); + case tok::kw___func__: IT = PreDefinedExpr::Func; break; // [C99 6.4.2.2] + case tok::kw___FUNCTION__: IT = PreDefinedExpr::Function; break; + case tok::kw___PRETTY_FUNCTION__: IT = PreDefinedExpr::PrettyFunction; break; + } + + // Verify that this is in a function context. + if (CurFunctionDecl == 0 && CurMethodDecl == 0) + return Diag(Loc, diag::err_predef_outside_function); + + // Pre-defined identifiers are of type char[x], where x is the length of the + // string. + unsigned Length; + if (CurFunctionDecl) + Length = CurFunctionDecl->getIdentifier()->getLength(); + else + Length = CurMethodDecl->getSynthesizedMethodSize(); + + llvm::APInt LengthI(32, Length + 1); + QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const); + ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); + return new PreDefinedExpr(Loc, ResTy, IT); +} + +Sema::ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { + llvm::SmallString<16> CharBuffer; + CharBuffer.resize(Tok.getLength()); + const char *ThisTokBegin = &CharBuffer[0]; + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); + + CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + Tok.getLocation(), PP); + if (Literal.hadError()) + return ExprResult(true); + + QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy; + + return new CharacterLiteral(Literal.getValue(), type, Tok.getLocation()); +} + +Action::ExprResult Sema::ActOnNumericConstant(const Token &Tok) { + // fast path for a single digit (which is quite common). A single digit + // cannot have a trigraph, escaped newline, radix prefix, or type suffix. + if (Tok.getLength() == 1) { + const char *t = PP.getSourceManager().getCharacterData(Tok.getLocation()); + + unsigned IntSize =static_cast(Context.getTypeSize(Context.IntTy)); + return ExprResult(new IntegerLiteral(llvm::APInt(IntSize, *t-'0'), + Context.IntTy, + Tok.getLocation())); + } + llvm::SmallString<512> IntegerBuffer; + IntegerBuffer.resize(Tok.getLength()); + const char *ThisTokBegin = &IntegerBuffer[0]; + + // Get the spelling of the token, which eliminates trigraphs, etc. + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); + NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + Tok.getLocation(), PP); + if (Literal.hadError) + return ExprResult(true); + + Expr *Res; + + if (Literal.isFloatingLiteral()) { + QualType Ty; + const llvm::fltSemantics *Format; + + if (Literal.isFloat) { + Ty = Context.FloatTy; + Format = Context.Target.getFloatFormat(); + } else if (!Literal.isLong) { + Ty = Context.DoubleTy; + Format = Context.Target.getDoubleFormat(); + } else { + Ty = Context.LongDoubleTy; + Format = Context.Target.getLongDoubleFormat(); + } + + // isExact will be set by GetFloatValue(). + bool isExact = false; + + Res = new FloatingLiteral(Literal.GetFloatValue(*Format,&isExact), &isExact, + Ty, Tok.getLocation()); + + } else if (!Literal.isIntegerLiteral()) { + return ExprResult(true); + } else { + QualType t; + + // long long is a C99 feature. + if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && + Literal.isLongLong) + Diag(Tok.getLocation(), diag::ext_longlong); + + // Get the value in the widest-possible width. + llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0); + + if (Literal.GetIntegerValue(ResultVal)) { + // If this value didn't fit into uintmax_t, warn and force to ull. + Diag(Tok.getLocation(), diag::warn_integer_too_large); + t = Context.UnsignedLongLongTy; + assert(Context.getTypeSize(t) == ResultVal.getBitWidth() && + "long long is not intmax_t?"); + } else { + // If this value fits into a ULL, try to figure out what else it fits into + // according to the rules of C99 6.4.4.1p5. + + // Octal, Hexadecimal, and integers with a U suffix are allowed to + // be an unsigned int. + bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10; + + // Check from smallest to largest, picking the smallest type we can. + if (!Literal.isLong && !Literal.isLongLong) { + // Are int/unsigned possibilities? + unsigned IntSize = + static_cast(Context.getTypeSize(Context.IntTy)); + // Does it fit in a unsigned int? + if (ResultVal.isIntN(IntSize)) { + // Does it fit in a signed int? + if (!Literal.isUnsigned && ResultVal[IntSize-1] == 0) + t = Context.IntTy; + else if (AllowUnsigned) + t = Context.UnsignedIntTy; + } + + if (!t.isNull()) + ResultVal.trunc(IntSize); + } + + // Are long/unsigned long possibilities? + if (t.isNull() && !Literal.isLongLong) { + unsigned LongSize = + static_cast(Context.getTypeSize(Context.LongTy)); + + // Does it fit in a unsigned long? + if (ResultVal.isIntN(LongSize)) { + // Does it fit in a signed long? + if (!Literal.isUnsigned && ResultVal[LongSize-1] == 0) + t = Context.LongTy; + else if (AllowUnsigned) + t = Context.UnsignedLongTy; + } + if (!t.isNull()) + ResultVal.trunc(LongSize); + } + + // Finally, check long long if needed. + if (t.isNull()) { + unsigned LongLongSize = + static_cast(Context.getTypeSize(Context.LongLongTy)); + + // Does it fit in a unsigned long long? + if (ResultVal.isIntN(LongLongSize)) { + // Does it fit in a signed long long? + if (!Literal.isUnsigned && ResultVal[LongLongSize-1] == 0) + t = Context.LongLongTy; + else if (AllowUnsigned) + t = Context.UnsignedLongLongTy; + } + } + + // If we still couldn't decide a type, we probably have something that + // does not fit in a signed long long, but has no U suffix. + if (t.isNull()) { + Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed); + t = Context.UnsignedLongLongTy; + } + } + + Res = new IntegerLiteral(ResultVal, t, Tok.getLocation()); + } + + // If this is an imaginary literal, create the ImaginaryLiteral wrapper. + if (Literal.isImaginary) + Res = new ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); + + return Res; +} + +Action::ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, + ExprTy *Val) { + Expr *e = (Expr *)Val; + assert((e != 0) && "ActOnParenExpr() missing expr"); + return new ParenExpr(L, R, e); +} + +/// The UsualUnaryConversions() function is *not* called by this routine. +/// See C99 6.3.2.1p[2-4] for more details. +QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType, + SourceLocation OpLoc, bool isSizeof) { + // C99 6.5.3.4p1: + if (isa(exprType) && isSizeof) + // alignof(function) is allowed. + Diag(OpLoc, diag::ext_sizeof_function_type); + else if (exprType->isVoidType()) + Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof"); + else if (exprType->isIncompleteType()) { + Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type : + diag::err_alignof_incomplete_type, + exprType.getAsString()); + return QualType(); // error + } + // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. + return Context.getSizeType(); +} + +Action::ExprResult Sema:: +ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof, + SourceLocation LPLoc, TypeTy *Ty, + SourceLocation RPLoc) { + // If error parsing type, ignore. + if (Ty == 0) return true; + + // Verify that this is a valid expression. + QualType ArgTy = QualType::getFromOpaquePtr(Ty); + + QualType resultType = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, isSizeof); + + if (resultType.isNull()) + return true; + return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, resultType, OpLoc, RPLoc); +} + +QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc) { + DefaultFunctionArrayConversion(V); + + // These operators return the element type of a complex type. + if (const ComplexType *CT = V->getType()->getAsComplexType()) + return CT->getElementType(); + + // Otherwise they pass through real integer and floating point types here. + if (V->getType()->isArithmeticType()) + return V->getType(); + + // Reject anything else. + Diag(Loc, diag::err_realimag_invalid_type, V->getType().getAsString()); + return QualType(); +} + + + +Action::ExprResult Sema::ActOnPostfixUnaryOp(SourceLocation OpLoc, + tok::TokenKind Kind, + ExprTy *Input) { + UnaryOperator::Opcode Opc; + switch (Kind) { + default: assert(0 && "Unknown unary op!"); + case tok::plusplus: Opc = UnaryOperator::PostInc; break; + case tok::minusminus: Opc = UnaryOperator::PostDec; break; + } + QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc); + if (result.isNull()) + return true; + return new UnaryOperator((Expr *)Input, Opc, result, OpLoc); +} + +Action::ExprResult Sema:: +ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, + ExprTy *Idx, SourceLocation RLoc) { + Expr *LHSExp = static_cast(Base), *RHSExp = static_cast(Idx); + + // Perform default conversions. + DefaultFunctionArrayConversion(LHSExp); + DefaultFunctionArrayConversion(RHSExp); + + QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); + + // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent + // to the expression *((e1)+(e2)). This means the array "Base" may actually be + // in the subscript position. As a result, we need to derive the array base + // and index from the expression types. + Expr *BaseExpr, *IndexExpr; + QualType ResultType; + if (const PointerType *PTy = LHSTy->getAsPointerType()) { + BaseExpr = LHSExp; + IndexExpr = RHSExp; + // FIXME: need to deal with const... + ResultType = PTy->getPointeeType(); + } else if (const PointerType *PTy = RHSTy->getAsPointerType()) { + // Handle the uncommon case of "123[Ptr]". + BaseExpr = RHSExp; + IndexExpr = LHSExp; + // FIXME: need to deal with const... + ResultType = PTy->getPointeeType(); + } else if (const VectorType *VTy = LHSTy->getAsVectorType()) { + BaseExpr = LHSExp; // vectors: V[123] + IndexExpr = RHSExp; + + // Component access limited to variables (reject vec4.rg[1]). + if (!isa(BaseExpr) && !isa(BaseExpr)) + return Diag(LLoc, diag::err_ocuvector_component_access, + SourceRange(LLoc, RLoc)); + // FIXME: need to deal with const... + ResultType = VTy->getElementType(); + } else { + return Diag(LHSExp->getLocStart(), diag::err_typecheck_subscript_value, + RHSExp->getSourceRange()); + } + // C99 6.5.2.1p1 + if (!IndexExpr->getType()->isIntegerType()) + return Diag(IndexExpr->getLocStart(), diag::err_typecheck_subscript, + IndexExpr->getSourceRange()); + + // C99 6.5.2.1p1: "shall have type "pointer to *object* type". In practice, + // the following check catches trying to index a pointer to a function (e.g. + // void (*)(int)). Functions are not objects in C99. + if (!ResultType->isObjectType()) + return Diag(BaseExpr->getLocStart(), + diag::err_typecheck_subscript_not_object, + BaseExpr->getType().getAsString(), BaseExpr->getSourceRange()); + + return new ArraySubscriptExpr(LHSExp, RHSExp, ResultType, RLoc); +} + +QualType Sema:: +CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc, + IdentifierInfo &CompName, SourceLocation CompLoc) { + const OCUVectorType *vecType = baseType->getAsOCUVectorType(); + + // The vector accessor can't exceed the number of elements. + const char *compStr = CompName.getName(); + if (strlen(compStr) > vecType->getNumElements()) { + Diag(OpLoc, diag::err_ocuvector_component_exceeds_length, + baseType.getAsString(), SourceRange(CompLoc)); + return QualType(); + } + // The component names must come from the same set. + if (vecType->getPointAccessorIdx(*compStr) != -1) { + do + compStr++; + while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1); + } else if (vecType->getColorAccessorIdx(*compStr) != -1) { + do + compStr++; + while (*compStr && vecType->getColorAccessorIdx(*compStr) != -1); + } else if (vecType->getTextureAccessorIdx(*compStr) != -1) { + do + compStr++; + while (*compStr && vecType->getTextureAccessorIdx(*compStr) != -1); + } + + if (*compStr) { + // We didn't get to the end of the string. This means the component names + // didn't come from the same set *or* we encountered an illegal name. + Diag(OpLoc, diag::err_ocuvector_component_name_illegal, + std::string(compStr,compStr+1), SourceRange(CompLoc)); + return QualType(); + } + // Each component accessor can't exceed the vector type. + compStr = CompName.getName(); + while (*compStr) { + if (vecType->isAccessorWithinNumElements(*compStr)) + compStr++; + else + break; + } + if (*compStr) { + // We didn't get to the end of the string. This means a component accessor + // exceeds the number of elements in the vector. + Diag(OpLoc, diag::err_ocuvector_component_exceeds_length, + baseType.getAsString(), SourceRange(CompLoc)); + return QualType(); + } + // The component accessor looks fine - now we need to compute the actual type. + // The vector type is implied by the component accessor. For example, + // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. + unsigned CompSize = strlen(CompName.getName()); + if (CompSize == 1) + return vecType->getElementType(); + + QualType VT = Context.getOCUVectorType(vecType->getElementType(), CompSize); + // Now look up the TypeDefDecl from the vector type. Without this, + // diagostics look bad. We want OCU vector types to appear built-in. + for (unsigned i = 0, e = OCUVectorDecls.size(); i != e; ++i) { + if (OCUVectorDecls[i]->getUnderlyingType() == VT) + return Context.getTypedefType(OCUVectorDecls[i]); + } + return VT; // should never get here (a typedef type should always be found). +} + +Action::ExprResult Sema:: +ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, + tok::TokenKind OpKind, SourceLocation MemberLoc, + IdentifierInfo &Member) { + Expr *BaseExpr = static_cast(Base); + assert(BaseExpr && "no record expression"); + + // Perform default conversions. + DefaultFunctionArrayConversion(BaseExpr); + + QualType BaseType = BaseExpr->getType(); + assert(!BaseType.isNull() && "no type for member expression"); + + if (OpKind == tok::arrow) { + if (const PointerType *PT = BaseType->getAsPointerType()) + BaseType = PT->getPointeeType(); + else + return Diag(OpLoc, diag::err_typecheck_member_reference_arrow, + SourceRange(MemberLoc)); + } + // The base type is either a record or an OCUVectorType. + if (const RecordType *RTy = BaseType->getAsRecordType()) { + RecordDecl *RDecl = RTy->getDecl(); + if (RTy->isIncompleteType()) + return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RDecl->getName(), + BaseExpr->getSourceRange()); + // The record definition is complete, now make sure the member is valid. + FieldDecl *MemberDecl = RDecl->getMember(&Member); + if (!MemberDecl) + return Diag(OpLoc, diag::err_typecheck_no_member, Member.getName(), + SourceRange(MemberLoc)); + + // Figure out the type of the member; see C99 6.5.2.3p3 + // FIXME: Handle address space modifiers + QualType MemberType = MemberDecl->getType(); + unsigned combinedQualifiers = + MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); + MemberType = MemberType.getQualifiedType(combinedQualifiers); + + return new MemberExpr(BaseExpr, OpKind==tok::arrow, MemberDecl, + MemberLoc, MemberType); + } else if (BaseType->isOCUVectorType() && OpKind == tok::period) { + // Component access limited to variables (reject vec4.rg.g). + if (!isa(BaseExpr)) + return Diag(OpLoc, diag::err_ocuvector_component_access, + SourceRange(MemberLoc)); + QualType ret = CheckOCUVectorComponent(BaseType, OpLoc, Member, MemberLoc); + if (ret.isNull()) + return true; + return new OCUVectorElementExpr(ret, BaseExpr, Member, MemberLoc); + } else if (BaseType->isObjCInterfaceType()) { + ObjCInterfaceDecl *IFace; + if (isa(BaseType.getCanonicalType())) + IFace = dyn_cast(BaseType)->getDecl(); + else + IFace = dyn_cast(BaseType)->getDecl(); + ObjCInterfaceDecl *clsDeclared; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&Member, clsDeclared)) + return new ObjCIvarRefExpr(IV, IV->getType(), MemberLoc, BaseExpr, + OpKind==tok::arrow); + } + return Diag(OpLoc, diag::err_typecheck_member_reference_structUnion, + SourceRange(MemberLoc)); +} + +/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. +/// This provides the location of the left/right parens and a list of comma +/// locations. +Action::ExprResult Sema:: +ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, + ExprTy **args, unsigned NumArgs, + SourceLocation *CommaLocs, SourceLocation RParenLoc) { + Expr *Fn = static_cast(fn); + Expr **Args = reinterpret_cast(args); + assert(Fn && "no function call expression"); + + // Make the call expr early, before semantic checks. This guarantees cleanup + // of arguments and function on error. + llvm::OwningPtr TheCall(new CallExpr(Fn, Args, NumArgs, + Context.BoolTy, RParenLoc)); + + // Promote the function operand. + TheCall->setCallee(UsualUnaryConversions(Fn)); + + // C99 6.5.2.2p1 - "The expression that denotes the called function shall have + // type pointer to function". + const PointerType *PT = Fn->getType()->getAsPointerType(); + if (PT == 0) + return Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function, + SourceRange(Fn->getLocStart(), RParenLoc)); + const FunctionType *FuncT = PT->getPointeeType()->getAsFunctionType(); + if (FuncT == 0) + return Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function, + SourceRange(Fn->getLocStart(), RParenLoc)); + + // We know the result type of the call, set it. + TheCall->setType(FuncT->getResultType()); + + if (const FunctionTypeProto *Proto = dyn_cast(FuncT)) { + // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by + // assignment, to the types of the corresponding parameter, ... + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned NumArgsToCheck = NumArgs; + + // If too few arguments are available, don't make the call. + if (NumArgs < NumArgsInProto) + return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, + Fn->getSourceRange()); + + // If too many are passed and not variadic, error on the extras and drop + // them. + if (NumArgs > NumArgsInProto) { + if (!Proto->isVariadic()) { + Diag(Args[NumArgsInProto]->getLocStart(), + diag::err_typecheck_call_too_many_args, Fn->getSourceRange(), + SourceRange(Args[NumArgsInProto]->getLocStart(), + Args[NumArgs-1]->getLocEnd())); + // This deletes the extra arguments. + TheCall->setNumArgs(NumArgsInProto); + } + NumArgsToCheck = NumArgsInProto; + } + + // Continue to check argument types (even if we have too few/many args). + for (unsigned i = 0; i != NumArgsToCheck; i++) { + Expr *Arg = Args[i]; + QualType ProtoArgType = Proto->getArgType(i); + QualType ArgType = Arg->getType(); + + // Compute implicit casts from the operand to the formal argument type. + AssignConvertType ConvTy = + CheckSingleAssignmentConstraints(ProtoArgType, Arg); + TheCall->setArg(i, Arg); + + if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), ProtoArgType, + ArgType, Arg, "passing")) + return true; + } + + // If this is a variadic call, handle args passed through "...". + if (Proto->isVariadic()) { + // Promote the arguments (C99 6.5.2.2p7). + for (unsigned i = NumArgsInProto; i != NumArgs; i++) { + Expr *Arg = Args[i]; + DefaultArgumentPromotion(Arg); + TheCall->setArg(i, Arg); + } + } + } else { + assert(isa(FuncT) && "Unknown FunctionType!"); + + // Promote the arguments (C99 6.5.2.2p6). + for (unsigned i = 0; i != NumArgs; i++) { + Expr *Arg = Args[i]; + DefaultArgumentPromotion(Arg); + TheCall->setArg(i, Arg); + } + } + + // Do special checking on direct calls to functions. + if (ImplicitCastExpr *IcExpr = dyn_cast(Fn)) + if (DeclRefExpr *DRExpr = dyn_cast(IcExpr->getSubExpr())) + if (FunctionDecl *FDecl = dyn_cast(DRExpr->getDecl())) + if (CheckFunctionCall(FDecl, TheCall.get())) + return true; + + return TheCall.take(); +} + +Action::ExprResult Sema:: +ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprTy *InitExpr) { + assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); + QualType literalType = QualType::getFromOpaquePtr(Ty); + // FIXME: put back this assert when initializers are worked out. + //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); + Expr *literalExpr = static_cast(InitExpr); + + // FIXME: add more semantic analysis (C99 6.5.2.5). + if (CheckInitializerTypes(literalExpr, literalType)) + return true; + + bool isFileScope = !CurFunctionDecl && !CurMethodDecl; + if (isFileScope) { // 6.5.2.5p3 + if (CheckForConstantInitializer(literalExpr, literalType)) + return true; + } + return new CompoundLiteralExpr(LParenLoc, literalType, literalExpr, isFileScope); +} + +Action::ExprResult Sema:: +ActOnInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit, + SourceLocation RBraceLoc) { + Expr **InitList = reinterpret_cast(initlist); + + // Semantic analysis for initializers is done by ActOnDeclarator() and + // CheckInitializer() - it requires knowledge of the object being intialized. + + InitListExpr *e = new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc); + e->setType(Context.VoidTy); // FIXME: just a place holder for now. + return e; +} + +bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { + assert(VectorTy->isVectorType() && "Not a vector type!"); + + if (Ty->isVectorType() || Ty->isIntegerType()) { + if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty)) + return Diag(R.getBegin(), + Ty->isVectorType() ? + diag::err_invalid_conversion_between_vectors : + diag::err_invalid_conversion_between_vector_and_integer, + VectorTy.getAsString().c_str(), + Ty.getAsString().c_str(), R); + } else + return Diag(R.getBegin(), + diag::err_invalid_conversion_between_vector_and_scalar, + VectorTy.getAsString().c_str(), + Ty.getAsString().c_str(), R); + + return false; +} + +Action::ExprResult Sema:: +ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprTy *Op) { + assert((Ty != 0) && (Op != 0) && "ActOnCastExpr(): missing type or expr"); + + Expr *castExpr = static_cast(Op); + QualType castType = QualType::getFromOpaquePtr(Ty); + + UsualUnaryConversions(castExpr); + + // C99 6.5.4p2: the cast type needs to be void or scalar and the expression + // type needs to be scalar. + if (!castType->isVoidType()) { // Cast to void allows any expr type. + if (!castType->isScalarType() && !castType->isVectorType()) + return Diag(LParenLoc, diag::err_typecheck_cond_expect_scalar, + castType.getAsString(), SourceRange(LParenLoc, RParenLoc)); + if (!castExpr->getType()->isScalarType() && + !castExpr->getType()->isVectorType()) + return Diag(castExpr->getLocStart(), + diag::err_typecheck_expect_scalar_operand, + castExpr->getType().getAsString(),castExpr->getSourceRange()); + + if (castExpr->getType()->isVectorType()) { + if (CheckVectorCast(SourceRange(LParenLoc, RParenLoc), + castExpr->getType(), castType)) + return true; + } else if (castType->isVectorType()) { + if (CheckVectorCast(SourceRange(LParenLoc, RParenLoc), + castType, castExpr->getType())) + return true; + } + } + return new CastExpr(castType, castExpr, LParenLoc); +} + +/// Note that lex is not null here, even if this is the gnu "x ?: y" extension. +/// In that case, lex = cond. +inline QualType Sema::CheckConditionalOperands( // C99 6.5.15 + Expr *&cond, Expr *&lex, Expr *&rex, SourceLocation questionLoc) { + UsualUnaryConversions(cond); + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); + QualType condT = cond->getType(); + QualType lexT = lex->getType(); + QualType rexT = rex->getType(); + + // first, check the condition. + if (!condT->isScalarType()) { // C99 6.5.15p2 + Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar, + condT.getAsString()); + return QualType(); + } + + // Now check the two expressions. + + // If both operands have arithmetic type, do the usual arithmetic conversions + // to find a common type: C99 6.5.15p3,5. + if (lexT->isArithmeticType() && rexT->isArithmeticType()) { + UsualArithmeticConversions(lex, rex); + return lex->getType(); + } + + // If both operands are the same structure or union type, the result is that + // type. + if (const RecordType *LHSRT = lexT->getAsRecordType()) { // C99 6.5.15p3 + if (const RecordType *RHSRT = rexT->getAsRecordType()) + if (LHSRT->getDecl() == RHSRT->getDecl()) + // "If both the operands have structure or union type, the result has + // that type." This implies that CV qualifiers are dropped. + return lexT.getUnqualifiedType(); + } + + // C99 6.5.15p5: "If both operands have void type, the result has void type." + if (lexT->isVoidType() && rexT->isVoidType()) + return lexT.getUnqualifiedType(); + + // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has + // the type of the other operand." + if (lexT->isPointerType() && rex->isNullPointerConstant(Context)) { + ImpCastExprToType(rex, lexT); // promote the null to a pointer. + return lexT; + } + if (rexT->isPointerType() && lex->isNullPointerConstant(Context)) { + ImpCastExprToType(lex, rexT); // promote the null to a pointer. + return rexT; + } + // Handle the case where both operands are pointers before we handle null + // pointer constants in case both operands are null pointer constants. + if (const PointerType *LHSPT = lexT->getAsPointerType()) { // C99 6.5.15p3,6 + if (const PointerType *RHSPT = rexT->getAsPointerType()) { + // get the "pointed to" types + QualType lhptee = LHSPT->getPointeeType(); + QualType rhptee = RHSPT->getPointeeType(); + + // ignore qualifiers on void (C99 6.5.15p3, clause 6) + if (lhptee->isVoidType() && + (rhptee->isObjectType() || rhptee->isIncompleteType())) { + // Figure out necessary qualifiers (C99 6.5.15p6) + QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers()); + QualType destType = Context.getPointerType(destPointee); + ImpCastExprToType(lex, destType); // add qualifiers if necessary + ImpCastExprToType(rex, destType); // promote to void* + return destType; + } + if (rhptee->isVoidType() && + (lhptee->isObjectType() || lhptee->isIncompleteType())) { + QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers()); + QualType destType = Context.getPointerType(destPointee); + ImpCastExprToType(lex, destType); // add qualifiers if necessary + ImpCastExprToType(rex, destType); // promote to void* + return destType; + } + + if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), + rhptee.getUnqualifiedType())) { + Diag(questionLoc, diag::warn_typecheck_cond_incompatible_pointers, + lexT.getAsString(), rexT.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + // In this situation, we assume void* type. No especially good + // reason, but this is what gcc does, and we do have to pick + // to get a consistent AST. + QualType voidPtrTy = Context.getPointerType(Context.VoidTy); + ImpCastExprToType(lex, voidPtrTy); + ImpCastExprToType(rex, voidPtrTy); + return voidPtrTy; + } + // The pointer types are compatible. + // C99 6.5.15p6: If both operands are pointers to compatible types *or* to + // differently qualified versions of compatible types, the result type is + // a pointer to an appropriately qualified version of the *composite* + // type. + // FIXME: Need to return the composite type. + // FIXME: Need to add qualifiers + return lexT; + } + } + + // Otherwise, the operands are not compatible. + Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands, + lexT.getAsString(), rexT.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + return QualType(); +} + +/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null +/// in the case of a the GNU conditional expr extension. +Action::ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + ExprTy *Cond, ExprTy *LHS, + ExprTy *RHS) { + Expr *CondExpr = (Expr *) Cond; + Expr *LHSExpr = (Expr *) LHS, *RHSExpr = (Expr *) RHS; + + // If this is the gnu "x ?: y" extension, analyze the types as though the LHS + // was the condition. + bool isLHSNull = LHSExpr == 0; + if (isLHSNull) + LHSExpr = CondExpr; + + QualType result = CheckConditionalOperands(CondExpr, LHSExpr, + RHSExpr, QuestionLoc); + if (result.isNull()) + return true; + return new ConditionalOperator(CondExpr, isLHSNull ? 0 : LHSExpr, + RHSExpr, result); +} + +/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that +/// do not have a prototype. Arguments that have type float are promoted to +/// double. All other argument types are converted by UsualUnaryConversions(). +void Sema::DefaultArgumentPromotion(Expr *&Expr) { + QualType Ty = Expr->getType(); + assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); + + if (Ty == Context.FloatTy) + ImpCastExprToType(Expr, Context.DoubleTy); + else + UsualUnaryConversions(Expr); +} + +/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). +void Sema::DefaultFunctionArrayConversion(Expr *&e) { + QualType t = e->getType(); + assert(!t.isNull() && "DefaultFunctionArrayConversion - missing type"); + + if (const ReferenceType *ref = t->getAsReferenceType()) { + ImpCastExprToType(e, ref->getReferenceeType()); // C++ [expr] + t = e->getType(); + } + if (t->isFunctionType()) + ImpCastExprToType(e, Context.getPointerType(t)); + else if (const ArrayType *ary = t->getAsArrayType()) { + // Make sure we don't lose qualifiers when dealing with typedefs. Example: + // typedef int arr[10]; + // void test2() { + // const arr b; + // b[4] = 1; + // } + QualType ELT = ary->getElementType(); + // FIXME: Handle ASQualType + ELT = ELT.getQualifiedType(t.getCVRQualifiers()|ELT.getCVRQualifiers()); + ImpCastExprToType(e, Context.getPointerType(ELT)); + } +} + +/// UsualUnaryConversions - Performs various conversions that are common to most +/// operators (C99 6.3). The conversions of array and function types are +/// sometimes surpressed. For example, the array->pointer conversion doesn't +/// apply if the array is an argument to the sizeof or address (&) operators. +/// In these instances, this routine should *not* be called. +Expr *Sema::UsualUnaryConversions(Expr *&Expr) { + QualType Ty = Expr->getType(); + assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); + + if (const ReferenceType *Ref = Ty->getAsReferenceType()) { + ImpCastExprToType(Expr, Ref->getReferenceeType()); // C++ [expr] + Ty = Expr->getType(); + } + if (Ty->isPromotableIntegerType()) // C99 6.3.1.1p2 + ImpCastExprToType(Expr, Context.IntTy); + else + DefaultFunctionArrayConversion(Expr); + + return Expr; +} + +/// UsualArithmeticConversions - Performs various conversions that are common to +/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this +/// routine returns the first non-arithmetic type found. The client is +/// responsible for emitting appropriate error diagnostics. +/// FIXME: verify the conversion rules for "complex int" are consistent with GCC. +QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, + bool isCompAssign) { + if (!isCompAssign) { + UsualUnaryConversions(lhsExpr); + UsualUnaryConversions(rhsExpr); + } + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType lhs = lhsExpr->getType().getCanonicalType().getUnqualifiedType(); + QualType rhs = rhsExpr->getType().getCanonicalType().getUnqualifiedType(); + + // If both types are identical, no conversion is needed. + if (lhs == rhs) + return lhs; + + // If either side is a non-arithmetic type (e.g. a pointer), we are done. + // The caller can deal with this (e.g. pointer + int). + if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) + return lhs; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + if (lhs->isComplexType() || rhs->isComplexType()) { + // if we have an integer operand, the result is the complex type. + if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { + // convert the rhs to the lhs complex type. + if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); + return lhs; + } + if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { + // convert the lhs to the rhs complex type. + if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); + return rhs; + } + // This handles complex/complex, complex/float, or float/complex. + // When both operands are complex, the shorter operand is converted to the + // type of the longer, and that is the type of the result. This corresponds + // to what is done when combining two real floating-point operands. + // The fun begins when size promotion occur across type domains. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + int result = Context.compareFloatingType(lhs, rhs); + + if (result > 0) { // The left side is bigger, convert rhs. + rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs); + if (!isCompAssign) + ImpCastExprToType(rhsExpr, rhs); + } else if (result < 0) { // The right side is bigger, convert lhs. + lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs); + if (!isCompAssign) + ImpCastExprToType(lhsExpr, lhs); + } + // At this point, lhs and rhs have the same rank/size. Now, make sure the + // domains match. This is a requirement for our implementation, C99 + // does not require this promotion. + if (lhs != rhs) { // Domains don't match, we have complex/float mix. + if (lhs->isRealFloatingType()) { // handle "double, _Complex double". + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs); + return rhs; + } else { // handle "_Complex double, double". + if (!isCompAssign) + ImpCastExprToType(rhsExpr, lhs); + return lhs; + } + } + return lhs; // The domain/size match exactly. + } + // Now handle "real" floating types (i.e. float, double, long double). + if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { + // if we have an integer operand, the result is the real floating type. + if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { + // convert rhs to the lhs floating point type. + if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); + return lhs; + } + if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { + // convert lhs to the rhs floating point type. + if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); + return rhs; + } + // We have two real floating types, float/complex combos were handled above. + // Convert the smaller operand to the bigger result. + int result = Context.compareFloatingType(lhs, rhs); + + if (result > 0) { // convert the rhs + if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); + return lhs; + } + if (result < 0) { // convert the lhs + if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs + return rhs; + } + assert(0 && "Sema::UsualArithmeticConversions(): illegal float comparison"); + } + if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { + // Handle GCC complex int extension. + const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); + const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); + + if (lhsComplexInt && rhsComplexInt) { + if (Context.maxIntegerType(lhsComplexInt->getElementType(), + rhsComplexInt->getElementType()) == lhs) { + // convert the rhs + if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); + return lhs; + } + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs); // convert the lhs + return rhs; + } else if (lhsComplexInt && rhs->isIntegerType()) { + // convert the rhs to the lhs complex type. + if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); + return lhs; + } else if (rhsComplexInt && lhs->isIntegerType()) { + // convert the lhs to the rhs complex type. + if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); + return rhs; + } + } + // Finally, we have two differing integer types. + if (Context.maxIntegerType(lhs, rhs) == lhs) { // convert the rhs + if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs); + return lhs; + } + if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs + return rhs; +} + +// CheckPointerTypesForAssignment - This is a very tricky routine (despite +// being closely modeled after the C99 spec:-). The odd characteristic of this +// routine is it effectively iqnores the qualifiers on the top level pointee. +// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. +// FIXME: add a couple examples in this comment. +Sema::AssignConvertType +Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { + QualType lhptee, rhptee; + + // get the "pointed to" type (ignoring qualifiers at the top level) + lhptee = lhsType->getAsPointerType()->getPointeeType(); + rhptee = rhsType->getAsPointerType()->getPointeeType(); + + // make sure we operate on the canonical type + lhptee = lhptee.getCanonicalType(); + rhptee = rhptee.getCanonicalType(); + + AssignConvertType ConvTy = Compatible; + + // C99 6.5.16.1p1: This following citation is common to constraints + // 3 & 4 (below). ...and the type *pointed to* by the left has all the + // qualifiers of the type *pointed to* by the right; + // FIXME: Handle ASQualType + if ((lhptee.getCVRQualifiers() & rhptee.getCVRQualifiers()) != + rhptee.getCVRQualifiers()) + ConvTy = CompatiblePointerDiscardsQualifiers; + + // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or + // incomplete type and the other is a pointer to a qualified or unqualified + // version of void... + if (lhptee->isVoidType()) { + if (rhptee->isObjectType() || rhptee->isIncompleteType()) + return ConvTy; + + // As an extension, we allow cast to/from void* to function pointer. + if (rhptee->isFunctionType()) + return FunctionVoidPointer; + } + + if (rhptee->isVoidType()) { + if (lhptee->isObjectType() || lhptee->isIncompleteType()) + return ConvTy; + + // As an extension, we allow cast to/from void* to function pointer. + if (lhptee->isFunctionType()) + return FunctionVoidPointer; + } + + // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or + // unqualified versions of compatible types, ... + if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), + rhptee.getUnqualifiedType())) + return IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers + return ConvTy; +} + +/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently +/// has code to accommodate several GCC extensions when type checking +/// pointers. Here are some objectionable examples that GCC considers warnings: +/// +/// int a, *pint; +/// short *pshort; +/// struct foo *pfoo; +/// +/// pint = pshort; // warning: assignment from incompatible pointer type +/// a = pint; // warning: assignment makes integer from pointer without a cast +/// pint = a; // warning: assignment makes pointer from integer without a cast +/// pint = pfoo; // warning: assignment from incompatible pointer type +/// +/// As a result, the code for dealing with pointers is more complex than the +/// C99 spec dictates. +/// Note: the warning above turn into errors when -pedantic-errors is enabled. +/// +Sema::AssignConvertType +Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { + // Get canonical types. We're not formatting these types, just comparing + // them. + lhsType = lhsType.getCanonicalType(); + rhsType = rhsType.getCanonicalType(); + + if (lhsType.getUnqualifiedType() == rhsType.getUnqualifiedType()) + return Compatible; // Common case: fast path an exact match. + + if (lhsType->isReferenceType() || rhsType->isReferenceType()) { + if (Context.referenceTypesAreCompatible(lhsType, rhsType)) + return Compatible; + return Incompatible; + } + + if (lhsType->isObjCQualifiedIdType() + || rhsType->isObjCQualifiedIdType()) { + if (Context.ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType)) + return Compatible; + return Incompatible; + } + + if (lhsType->isVectorType() || rhsType->isVectorType()) { + // For OCUVector, allow vector splats; float -> + if (const OCUVectorType *LV = lhsType->getAsOCUVectorType()) { + if (LV->getElementType().getTypePtr() == rhsType.getTypePtr()) + return Compatible; + } + + // If LHS and RHS are both vectors of integer or both vectors of floating + // point types, and the total vector length is the same, allow the + // conversion. This is a bitcast; no bits are changed but the result type + // is different. + if (getLangOptions().LaxVectorConversions && + lhsType->isVectorType() && rhsType->isVectorType()) { + if ((lhsType->isIntegerType() && rhsType->isIntegerType()) || + (lhsType->isRealFloatingType() && rhsType->isRealFloatingType())) { + if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) + return Compatible; + } + } + return Incompatible; + } + + if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) + return Compatible; + + if (lhsType->isPointerType()) { + if (rhsType->isIntegerType()) + return IntToPointer; + + if (rhsType->isPointerType()) + return CheckPointerTypesForAssignment(lhsType, rhsType); + return Incompatible; + } + + if (rhsType->isPointerType()) { + // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. + if ((lhsType->isIntegerType()) && (lhsType != Context.BoolTy)) + return PointerToInt; + + if (lhsType->isPointerType()) + return CheckPointerTypesForAssignment(lhsType, rhsType); + return Incompatible; + } + + if (isa(lhsType) && isa(rhsType)) { + if (Context.tagTypesAreCompatible(lhsType, rhsType)) + return Compatible; + } + return Incompatible; +} + +Sema::AssignConvertType +Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { + // C99 6.5.16.1p1: the left operand is a pointer and the right is + // a null pointer constant. + if ((lhsType->isPointerType() || lhsType->isObjCQualifiedIdType()) + && rExpr->isNullPointerConstant(Context)) { + ImpCastExprToType(rExpr, lhsType); + return Compatible; + } + // This check seems unnatural, however it is necessary to ensure the proper + // conversion of functions/arrays. If the conversion were done for all + // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary + // expressions that surpress this implicit conversion (&, sizeof). + // + // Suppress this for references: C99 8.5.3p5. FIXME: revisit when references + // are better understood. + if (!lhsType->isReferenceType()) + DefaultFunctionArrayConversion(rExpr); + + Sema::AssignConvertType result = + CheckAssignmentConstraints(lhsType, rExpr->getType()); + + // C99 6.5.16.1p2: The value of the right operand is converted to the + // type of the assignment expression. + if (rExpr->getType() != lhsType) + ImpCastExprToType(rExpr, lhsType); + return result; +} + +Sema::AssignConvertType +Sema::CheckCompoundAssignmentConstraints(QualType lhsType, QualType rhsType) { + return CheckAssignmentConstraints(lhsType, rhsType); +} + +QualType Sema::InvalidOperands(SourceLocation loc, Expr *&lex, Expr *&rex) { + Diag(loc, diag::err_typecheck_invalid_operands, + lex->getType().getAsString(), rex->getType().getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + return QualType(); +} + +inline QualType Sema::CheckVectorOperands(SourceLocation loc, Expr *&lex, + Expr *&rex) { + QualType lhsType = lex->getType(), rhsType = rex->getType(); + + // make sure the vector types are identical. + if (lhsType == rhsType) + return lhsType; + + // if the lhs is an ocu vector and the rhs is a scalar of the same type, + // promote the rhs to the vector type. + if (const OCUVectorType *V = lhsType->getAsOCUVectorType()) { + if (V->getElementType().getCanonicalType().getTypePtr() + == rhsType.getCanonicalType().getTypePtr()) { + ImpCastExprToType(rex, lhsType); + return lhsType; + } + } + + // if the rhs is an ocu vector and the lhs is a scalar of the same type, + // promote the lhs to the vector type. + if (const OCUVectorType *V = rhsType->getAsOCUVectorType()) { + if (V->getElementType().getCanonicalType().getTypePtr() + == lhsType.getCanonicalType().getTypePtr()) { + ImpCastExprToType(lex, rhsType); + return rhsType; + } + } + + // You cannot convert between vector values of different size. + Diag(loc, diag::err_typecheck_vector_not_convertable, + lex->getType().getAsString(), rex->getType().getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + return QualType(); +} + +inline QualType Sema::CheckMultiplyDivideOperands( + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) +{ + QualType lhsType = lex->getType(), rhsType = rex->getType(); + + if (lhsType->isVectorType() || rhsType->isVectorType()) + return CheckVectorOperands(loc, lex, rex); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + return compType; + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckRemainderOperands( + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) +{ + QualType lhsType = lex->getType(), rhsType = rex->getType(); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + return compType; + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(loc, lex, rex); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + // handle the common case first (both operands are arithmetic). + if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + return compType; + + if (lex->getType()->isPointerType() && rex->getType()->isIntegerType()) + return lex->getType(); + if (lex->getType()->isIntegerType() && rex->getType()->isPointerType()) + return rex->getType(); + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(loc, lex, rex); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + // Enforce type constraints: C99 6.5.6p3. + + // Handle the common case first (both operands are arithmetic). + if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + return compType; + + // Either ptr - int or ptr - ptr. + if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { + QualType lpointee = LHSPTy->getPointeeType(); + + // The LHS must be an object type, not incomplete, function, etc. + if (!lpointee->isObjectType()) { + // Handle the GNU void* extension. + if (lpointee->isVoidType()) { + Diag(loc, diag::ext_gnu_void_ptr, + lex->getSourceRange(), rex->getSourceRange()); + } else { + Diag(loc, diag::err_typecheck_sub_ptr_object, + lex->getType().getAsString(), lex->getSourceRange()); + return QualType(); + } + } + + // The result type of a pointer-int computation is the pointer type. + if (rex->getType()->isIntegerType()) + return lex->getType(); + + // Handle pointer-pointer subtractions. + if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) { + QualType rpointee = RHSPTy->getPointeeType(); + + // RHS must be an object type, unless void (GNU). + if (!rpointee->isObjectType()) { + // Handle the GNU void* extension. + if (rpointee->isVoidType()) { + if (!lpointee->isVoidType()) + Diag(loc, diag::ext_gnu_void_ptr, + lex->getSourceRange(), rex->getSourceRange()); + } else { + Diag(loc, diag::err_typecheck_sub_ptr_object, + rex->getType().getAsString(), rex->getSourceRange()); + return QualType(); + } + } + + // Pointee types must be compatible. + if (!Context.typesAreCompatible(lpointee.getUnqualifiedType(), + rpointee.getUnqualifiedType())) { + Diag(loc, diag::err_typecheck_sub_ptr_compatible, + lex->getType().getAsString(), rex->getType().getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + return QualType(); + } + + return Context.getPointerDiffType(); + } + } + + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckShiftOperands( // C99 6.5.7 + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) { + // C99 6.5.7p2: Each of the operands shall have integer type. + if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + return InvalidOperands(loc, lex, rex); + + // Shifts don't perform usual arithmetic conversions, they just do integer + // promotions on each operand. C99 6.5.7p3 + if (!isCompAssign) + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); + + // "The type of the result is that of the promoted left operand." + return lex->getType(); +} + +inline QualType Sema::CheckCompareOperands( // C99 6.5.8 + Expr *&lex, Expr *&rex, SourceLocation loc, bool isRelational) +{ + // C99 6.5.8p3 / C99 6.5.9p4 + if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + UsualArithmeticConversions(lex, rex); + else { + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); + } + QualType lType = lex->getType(); + QualType rType = rex->getType(); + + // For non-floating point types, check for self-comparisons of the form + // x == x, x != x, x < x, etc. These always evaluate to a constant, and + // often indicate logic errors in the program. + if (!lType->isFloatingType()) { + if (DeclRefExpr* DRL = dyn_cast(lex->IgnoreParens())) + if (DeclRefExpr* DRR = dyn_cast(rex->IgnoreParens())) + if (DRL->getDecl() == DRR->getDecl()) + Diag(loc, diag::warn_selfcomparison); + } + + if (isRelational) { + if (lType->isRealType() && rType->isRealType()) + return Context.IntTy; + } else { + // Check for comparisons of floating point operands using != and ==. + if (lType->isFloatingType()) { + assert (rType->isFloatingType()); + CheckFloatComparison(loc,lex,rex); + } + + if (lType->isArithmeticType() && rType->isArithmeticType()) + return Context.IntTy; + } + + bool LHSIsNull = lex->isNullPointerConstant(Context); + bool RHSIsNull = rex->isNullPointerConstant(Context); + + // All of the following pointer related warnings are GCC extensions, except + // when handling null pointer constants. One day, we can consider making them + // errors (when -pedantic-errors is enabled). + if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2 + QualType lpointee = lType->getAsPointerType()->getPointeeType(); + QualType rpointee = rType->getAsPointerType()->getPointeeType(); + + if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2 + !lpointee->isVoidType() && !lpointee->isVoidType() && + !Context.typesAreCompatible(lpointee.getUnqualifiedType(), + rpointee.getUnqualifiedType())) { + Diag(loc, diag::ext_typecheck_comparison_of_distinct_pointers, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + } + ImpCastExprToType(rex, lType); // promote the pointer to pointer + return Context.IntTy; + } + if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType()) + && Context.ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) { + ImpCastExprToType(rex, lType); + return Context.IntTy; + } + if (lType->isPointerType() && rType->isIntegerType()) { + if (!RHSIsNull) + Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + ImpCastExprToType(rex, lType); // promote the integer to pointer + return Context.IntTy; + } + if (lType->isIntegerType() && rType->isPointerType()) { + if (!LHSIsNull) + Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer, + lType.getAsString(), rType.getAsString(), + lex->getSourceRange(), rex->getSourceRange()); + ImpCastExprToType(lex, rType); // promote the integer to pointer + return Context.IntTy; + } + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckBitwiseOperands( + Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(loc, lex, rex); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + return compType; + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] + Expr *&lex, Expr *&rex, SourceLocation loc) +{ + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); + + if (lex->getType()->isScalarType() || rex->getType()->isScalarType()) + return Context.IntTy; + return InvalidOperands(loc, lex, rex); +} + +inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1 + Expr *lex, Expr *&rex, SourceLocation loc, QualType compoundType) +{ + QualType lhsType = lex->getType(); + QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType; + Expr::isModifiableLvalueResult mlval = lex->isModifiableLvalue(); + + switch (mlval) { // C99 6.5.16p2 + case Expr::MLV_Valid: + break; + case Expr::MLV_ConstQualified: + Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange()); + return QualType(); + case Expr::MLV_ArrayType: + Diag(loc, diag::err_typecheck_array_not_modifiable_lvalue, + lhsType.getAsString(), lex->getSourceRange()); + return QualType(); + case Expr::MLV_NotObjectType: + Diag(loc, diag::err_typecheck_non_object_not_modifiable_lvalue, + lhsType.getAsString(), lex->getSourceRange()); + return QualType(); + case Expr::MLV_InvalidExpression: + Diag(loc, diag::err_typecheck_expression_not_modifiable_lvalue, + lex->getSourceRange()); + return QualType(); + case Expr::MLV_IncompleteType: + case Expr::MLV_IncompleteVoidType: + Diag(loc, diag::err_typecheck_incomplete_type_not_modifiable_lvalue, + lhsType.getAsString(), lex->getSourceRange()); + return QualType(); + case Expr::MLV_DuplicateVectorComponents: + Diag(loc, diag::err_typecheck_duplicate_vector_components_not_mlvalue, + lex->getSourceRange()); + return QualType(); + } + + AssignConvertType ConvTy; + if (compoundType.isNull()) + ConvTy = CheckSingleAssignmentConstraints(lhsType, rex); + else + ConvTy = CheckCompoundAssignmentConstraints(lhsType, rhsType); + + if (DiagnoseAssignmentResult(ConvTy, loc, lhsType, rhsType, + rex, "assigning")) + return QualType(); + + // C99 6.5.16p3: The type of an assignment expression is the type of the + // left operand unless the left operand has qualified type, in which case + // it is the unqualified version of the type of the left operand. + // C99 6.5.16.1p2: In simple assignment, the value of the right operand + // is converted to the type of the assignment expression (above). + // C++ 5.17p1: the type of the assignment expression is that of its left + // oprdu. + return lhsType.getUnqualifiedType(); +} + +inline QualType Sema::CheckCommaOperands( // C99 6.5.17 + Expr *&lex, Expr *&rex, SourceLocation loc) { + UsualUnaryConversions(rex); + return rex->getType(); +} + +/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine +/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. +QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) { + QualType resType = op->getType(); + assert(!resType.isNull() && "no type for increment/decrement expression"); + + // C99 6.5.2.4p1: We allow complex as a GCC extension. + if (const PointerType *pt = resType->getAsPointerType()) { + if (!pt->getPointeeType()->isObjectType()) { // C99 6.5.2.4p2, 6.5.6p2 + Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type, + resType.getAsString(), op->getSourceRange()); + return QualType(); + } + } else if (!resType->isRealType()) { + if (resType->isComplexType()) + // C99 does not support ++/-- on complex types. + Diag(OpLoc, diag::ext_integer_increment_complex, + resType.getAsString(), op->getSourceRange()); + else { + Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement, + resType.getAsString(), op->getSourceRange()); + return QualType(); + } + } + // At this point, we know we have a real, complex or pointer type. + // Now make sure the operand is a modifiable lvalue. + Expr::isModifiableLvalueResult mlval = op->isModifiableLvalue(); + if (mlval != Expr::MLV_Valid) { + // FIXME: emit a more precise diagnostic... + Diag(OpLoc, diag::err_typecheck_invalid_lvalue_incr_decr, + op->getSourceRange()); + return QualType(); + } + return resType; +} + +/// getPrimaryDecl - Helper function for CheckAddressOfOperand(). +/// This routine allows us to typecheck complex/recursive expressions +/// where the declaration is needed for type checking. Here are some +/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2]. +static ValueDecl *getPrimaryDecl(Expr *e) { + switch (e->getStmtClass()) { + case Stmt::DeclRefExprClass: + return cast(e)->getDecl(); + case Stmt::MemberExprClass: + // Fields cannot be declared with a 'register' storage class. + // &X->f is always ok, even if X is declared register. + if (cast(e)->isArrow()) + return 0; + return getPrimaryDecl(cast(e)->getBase()); + case Stmt::ArraySubscriptExprClass: { + // &X[4] and &4[X] is invalid if X is invalid and X is not a pointer. + + ValueDecl *VD = getPrimaryDecl(cast(e)->getBase()); + if (!VD || VD->getType()->isPointerType()) + return 0; + else + return VD; + } + case Stmt::UnaryOperatorClass: + return getPrimaryDecl(cast(e)->getSubExpr()); + case Stmt::ParenExprClass: + return getPrimaryDecl(cast(e)->getSubExpr()); + case Stmt::ImplicitCastExprClass: + // &X[4] when X is an array, has an implicit cast from array to pointer. + return getPrimaryDecl(cast(e)->getSubExpr()); + default: + return 0; + } +} + +/// CheckAddressOfOperand - The operand of & must be either a function +/// designator or an lvalue designating an object. If it is an lvalue, the +/// object cannot be declared with storage class register or be a bit field. +/// Note: The usual conversions are *not* applied to the operand of the & +/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. +QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { + if (getLangOptions().C99) { + // Implement C99-only parts of addressof rules. + if (UnaryOperator* uOp = dyn_cast(op)) { + if (uOp->getOpcode() == UnaryOperator::Deref) + // Per C99 6.5.3.2, the address of a deref always returns a valid result + // (assuming the deref expression is valid). + return uOp->getSubExpr()->getType(); + } + // Technically, there should be a check for array subscript + // expressions here, but the result of one is always an lvalue anyway. + } + ValueDecl *dcl = getPrimaryDecl(op); + Expr::isLvalueResult lval = op->isLvalue(); + + if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1 + if (!dcl || !isa(dcl)) {// allow function designators + // FIXME: emit more specific diag... + Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof, + op->getSourceRange()); + return QualType(); + } + } else if (MemberExpr *MemExpr = dyn_cast(op)) { // C99 6.5.3.2p1 + if (MemExpr->getMemberDecl()->isBitField()) { + Diag(OpLoc, diag::err_typecheck_address_of, + std::string("bit-field"), op->getSourceRange()); + return QualType(); + } + // Check for Apple extension for accessing vector components. + } else if (isa(op) && + cast(op)->getBase()->getType()->isVectorType()) { + Diag(OpLoc, diag::err_typecheck_address_of, + std::string("vector"), op->getSourceRange()); + return QualType(); + } else if (dcl) { // C99 6.5.3.2p1 + // We have an lvalue with a decl. Make sure the decl is not declared + // with the register storage-class specifier. + if (const VarDecl *vd = dyn_cast(dcl)) { + if (vd->getStorageClass() == VarDecl::Register) { + Diag(OpLoc, diag::err_typecheck_address_of, + std::string("register variable"), op->getSourceRange()); + return QualType(); + } + } else + assert(0 && "Unknown/unexpected decl type"); + } + // If the operand has type "type", the result has type "pointer to type". + return Context.getPointerType(op->getType()); +} + +QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) { + UsualUnaryConversions(op); + QualType qType = op->getType(); + + if (const PointerType *PT = qType->getAsPointerType()) { + // Note that per both C89 and C99, this is always legal, even + // if ptype is an incomplete type or void. + // It would be possible to warn about dereferencing a + // void pointer, but it's completely well-defined, + // and such a warning is unlikely to catch any mistakes. + return PT->getPointeeType(); + } + Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer, + qType.getAsString(), op->getSourceRange()); + return QualType(); +} + +static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode( + tok::TokenKind Kind) { + BinaryOperator::Opcode Opc; + switch (Kind) { + default: assert(0 && "Unknown binop!"); + case tok::star: Opc = BinaryOperator::Mul; break; + case tok::slash: Opc = BinaryOperator::Div; break; + case tok::percent: Opc = BinaryOperator::Rem; break; + case tok::plus: Opc = BinaryOperator::Add; break; + case tok::minus: Opc = BinaryOperator::Sub; break; + case tok::lessless: Opc = BinaryOperator::Shl; break; + case tok::greatergreater: Opc = BinaryOperator::Shr; break; + case tok::lessequal: Opc = BinaryOperator::LE; break; + case tok::less: Opc = BinaryOperator::LT; break; + case tok::greaterequal: Opc = BinaryOperator::GE; break; + case tok::greater: Opc = BinaryOperator::GT; break; + case tok::exclaimequal: Opc = BinaryOperator::NE; break; + case tok::equalequal: Opc = BinaryOperator::EQ; break; + case tok::amp: Opc = BinaryOperator::And; break; + case tok::caret: Opc = BinaryOperator::Xor; break; + case tok::pipe: Opc = BinaryOperator::Or; break; + case tok::ampamp: Opc = BinaryOperator::LAnd; break; + case tok::pipepipe: Opc = BinaryOperator::LOr; break; + case tok::equal: Opc = BinaryOperator::Assign; break; + case tok::starequal: Opc = BinaryOperator::MulAssign; break; + case tok::slashequal: Opc = BinaryOperator::DivAssign; break; + case tok::percentequal: Opc = BinaryOperator::RemAssign; break; + case tok::plusequal: Opc = BinaryOperator::AddAssign; break; + case tok::minusequal: Opc = BinaryOperator::SubAssign; break; + case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break; + case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break; + case tok::ampequal: Opc = BinaryOperator::AndAssign; break; + case tok::caretequal: Opc = BinaryOperator::XorAssign; break; + case tok::pipeequal: Opc = BinaryOperator::OrAssign; break; + case tok::comma: Opc = BinaryOperator::Comma; break; + } + return Opc; +} + +static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode( + tok::TokenKind Kind) { + UnaryOperator::Opcode Opc; + switch (Kind) { + default: assert(0 && "Unknown unary op!"); + case tok::plusplus: Opc = UnaryOperator::PreInc; break; + case tok::minusminus: Opc = UnaryOperator::PreDec; break; + case tok::amp: Opc = UnaryOperator::AddrOf; break; + case tok::star: Opc = UnaryOperator::Deref; break; + case tok::plus: Opc = UnaryOperator::Plus; break; + case tok::minus: Opc = UnaryOperator::Minus; break; + case tok::tilde: Opc = UnaryOperator::Not; break; + case tok::exclaim: Opc = UnaryOperator::LNot; break; + case tok::kw_sizeof: Opc = UnaryOperator::SizeOf; break; + case tok::kw___alignof: Opc = UnaryOperator::AlignOf; break; + case tok::kw___real: Opc = UnaryOperator::Real; break; + case tok::kw___imag: Opc = UnaryOperator::Imag; break; + case tok::kw___extension__: Opc = UnaryOperator::Extension; break; + } + return Opc; +} + +// Binary Operators. 'Tok' is the token for the operator. +Action::ExprResult Sema::ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind, + ExprTy *LHS, ExprTy *RHS) { + BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind); + Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS; + + assert((lhs != 0) && "ActOnBinOp(): missing left expression"); + assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + + QualType ResultTy; // Result type of the binary operator. + QualType CompTy; // Computation type for compound assignments (e.g. '+=') + + switch (Opc) { + default: + assert(0 && "Unknown binary expr!"); + case BinaryOperator::Assign: + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, QualType()); + break; + case BinaryOperator::Mul: + case BinaryOperator::Div: + ResultTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::Rem: + ResultTy = CheckRemainderOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::Add: + ResultTy = CheckAdditionOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::Sub: + ResultTy = CheckSubtractionOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::Shl: + case BinaryOperator::Shr: + ResultTy = CheckShiftOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::LE: + case BinaryOperator::LT: + case BinaryOperator::GE: + case BinaryOperator::GT: + ResultTy = CheckCompareOperands(lhs, rhs, TokLoc, true); + break; + case BinaryOperator::EQ: + case BinaryOperator::NE: + ResultTy = CheckCompareOperands(lhs, rhs, TokLoc, false); + break; + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + ResultTy = CheckBitwiseOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + ResultTy = CheckLogicalOperands(lhs, rhs, TokLoc); + break; + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + CompTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc, true); + if (!CompTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); + break; + case BinaryOperator::RemAssign: + CompTy = CheckRemainderOperands(lhs, rhs, TokLoc, true); + if (!CompTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); + break; + case BinaryOperator::AddAssign: + CompTy = CheckAdditionOperands(lhs, rhs, TokLoc, true); + if (!CompTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); + break; + case BinaryOperator::SubAssign: + CompTy = CheckSubtractionOperands(lhs, rhs, TokLoc, true); + if (!CompTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); + break; + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + CompTy = CheckShiftOperands(lhs, rhs, TokLoc, true); + if (!CompTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); + break; + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: + CompTy = CheckBitwiseOperands(lhs, rhs, TokLoc, true); + if (!CompTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy); + break; + case BinaryOperator::Comma: + ResultTy = CheckCommaOperands(lhs, rhs, TokLoc); + break; + } + if (ResultTy.isNull()) + return true; + if (CompTy.isNull()) + return new BinaryOperator(lhs, rhs, Opc, ResultTy, TokLoc); + else + return new CompoundAssignOperator(lhs, rhs, Opc, ResultTy, CompTy, TokLoc); +} + +// Unary Operators. 'Tok' is the token for the operator. +Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op, + ExprTy *input) { + Expr *Input = (Expr*)input; + UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); + QualType resultType; + switch (Opc) { + default: + assert(0 && "Unimplemented unary expr!"); + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + resultType = CheckIncrementDecrementOperand(Input, OpLoc); + break; + case UnaryOperator::AddrOf: + resultType = CheckAddressOfOperand(Input, OpLoc); + break; + case UnaryOperator::Deref: + DefaultFunctionArrayConversion(Input); + resultType = CheckIndirectionOperand(Input, OpLoc); + break; + case UnaryOperator::Plus: + case UnaryOperator::Minus: + UsualUnaryConversions(Input); + resultType = Input->getType(); + if (!resultType->isArithmeticType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, + resultType.getAsString()); + break; + case UnaryOperator::Not: // bitwise complement + UsualUnaryConversions(Input); + resultType = Input->getType(); + // C99 6.5.3.3p1. We allow complex as a GCC extension. + if (!resultType->isIntegerType()) { + if (resultType->isComplexType()) + // C99 does not support '~' for complex conjugation. + Diag(OpLoc, diag::ext_integer_complement_complex, + resultType.getAsString()); + else + return Diag(OpLoc, diag::err_typecheck_unary_expr, + resultType.getAsString()); + } + break; + case UnaryOperator::LNot: // logical negation + // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). + DefaultFunctionArrayConversion(Input); + resultType = Input->getType(); + if (!resultType->isScalarType()) // C99 6.5.3.3p1 + return Diag(OpLoc, diag::err_typecheck_unary_expr, + resultType.getAsString()); + // LNot always has type int. C99 6.5.3.3p5. + resultType = Context.IntTy; + break; + case UnaryOperator::SizeOf: + resultType = CheckSizeOfAlignOfOperand(Input->getType(), OpLoc, true); + break; + case UnaryOperator::AlignOf: + resultType = CheckSizeOfAlignOfOperand(Input->getType(), OpLoc, false); + break; + case UnaryOperator::Real: + case UnaryOperator::Imag: + resultType = CheckRealImagOperand(Input, OpLoc); + break; + case UnaryOperator::Extension: + resultType = Input->getType(); + break; + } + if (resultType.isNull()) + return true; + return new UnaryOperator(Input, Opc, resultType, OpLoc); +} + +/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". +Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, + SourceLocation LabLoc, + IdentifierInfo *LabelII) { + // Look up the record for this label identifier. + LabelStmt *&LabelDecl = LabelMap[LabelII]; + + // If we haven't seen this label yet, create a forward reference. + if (LabelDecl == 0) + LabelDecl = new LabelStmt(LabLoc, LabelII, 0); + + // Create the AST node. The address of a label always has type 'void*'. + return new AddrLabelExpr(OpLoc, LabLoc, LabelDecl, + Context.getPointerType(Context.VoidTy)); +} + +Sema::ExprResult Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtTy *substmt, + SourceLocation RPLoc) { // "({..})" + Stmt *SubStmt = static_cast(substmt); + assert(SubStmt && isa(SubStmt) && "Invalid action invocation!"); + CompoundStmt *Compound = cast(SubStmt); + + // FIXME: there are a variety of strange constraints to enforce here, for + // example, it is not possible to goto into a stmt expression apparently. + // More semantic analysis is needed. + + // FIXME: the last statement in the compount stmt has its value used. We + // should not warn about it being unused. + + // If there are sub stmts in the compound stmt, take the type of the last one + // as the type of the stmtexpr. + QualType Ty = Context.VoidTy; + + if (!Compound->body_empty()) + if (Expr *LastExpr = dyn_cast(Compound->body_back())) + Ty = LastExpr->getType(); + + return new StmtExpr(Compound, Ty, LPLoc, RPLoc); +} + +Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + TypeTy *argty, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RPLoc) { + QualType ArgTy = QualType::getFromOpaquePtr(argty); + assert(!ArgTy.isNull() && "Missing type argument!"); + + // We must have at least one component that refers to the type, and the first + // one is known to be a field designator. Verify that the ArgTy represents + // a struct/union/class. + if (!ArgTy->isRecordType()) + return Diag(TypeLoc, diag::err_offsetof_record_type,ArgTy.getAsString()); + + // Otherwise, create a compound literal expression as the base, and + // iteratively process the offsetof designators. + Expr *Res = new CompoundLiteralExpr(SourceLocation(), ArgTy, 0, false); + + // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a + // GCC extension, diagnose them. + if (NumComponents != 1) + Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator, + SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd)); + + for (unsigned i = 0; i != NumComponents; ++i) { + const OffsetOfComponent &OC = CompPtr[i]; + if (OC.isBrackets) { + // Offset of an array sub-field. TODO: Should we allow vector elements? + const ArrayType *AT = Res->getType()->getAsArrayType(); + if (!AT) { + delete Res; + return Diag(OC.LocEnd, diag::err_offsetof_array_type, + Res->getType().getAsString()); + } + + // FIXME: C++: Verify that operator[] isn't overloaded. + + // C99 6.5.2.1p1 + Expr *Idx = static_cast(OC.U.E); + if (!Idx->getType()->isIntegerType()) + return Diag(Idx->getLocStart(), diag::err_typecheck_subscript, + Idx->getSourceRange()); + + Res = new ArraySubscriptExpr(Res, Idx, AT->getElementType(), OC.LocEnd); + continue; + } + + const RecordType *RC = Res->getType()->getAsRecordType(); + if (!RC) { + delete Res; + return Diag(OC.LocEnd, diag::err_offsetof_record_type, + Res->getType().getAsString()); + } + + // Get the decl corresponding to this. + RecordDecl *RD = RC->getDecl(); + FieldDecl *MemberDecl = RD->getMember(OC.U.IdentInfo); + if (!MemberDecl) + return Diag(BuiltinLoc, diag::err_typecheck_no_member, + OC.U.IdentInfo->getName(), + SourceRange(OC.LocStart, OC.LocEnd)); + + // FIXME: C++: Verify that MemberDecl isn't a static field. + // FIXME: Verify that MemberDecl isn't a bitfield. + // MemberDecl->getType() doesn't get the right qualifiers, but it doesn't + // matter here. + Res = new MemberExpr(Res, false, MemberDecl, OC.LocEnd, MemberDecl->getType()); + } + + return new UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(), + BuiltinLoc); +} + + +Sema::ExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeTy *arg1, TypeTy *arg2, + SourceLocation RPLoc) { + QualType argT1 = QualType::getFromOpaquePtr(arg1); + QualType argT2 = QualType::getFromOpaquePtr(arg2); + + assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); + + return new TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1, argT2,RPLoc); +} + +Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond, + ExprTy *expr1, ExprTy *expr2, + SourceLocation RPLoc) { + Expr *CondExpr = static_cast(cond); + Expr *LHSExpr = static_cast(expr1); + Expr *RHSExpr = static_cast(expr2); + + assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); + + // The conditional expression is required to be a constant expression. + llvm::APSInt condEval(32); + SourceLocation ExpLoc; + if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc)) + return Diag(ExpLoc, diag::err_typecheck_choose_expr_requires_constant, + CondExpr->getSourceRange()); + + // If the condition is > zero, then the AST type is the same as the LSHExpr. + QualType resType = condEval.getZExtValue() ? LHSExpr->getType() : + RHSExpr->getType(); + return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc); +} + +/// ExprsMatchFnType - return true if the Exprs in array Args have +/// QualTypes that match the QualTypes of the arguments of the FnType. +/// The number of arguments has already been validated to match the number of +/// arguments in FnType. +static bool ExprsMatchFnType(Expr **Args, const FunctionTypeProto *FnType) { + unsigned NumParams = FnType->getNumArgs(); + for (unsigned i = 0; i != NumParams; ++i) + if (Args[i]->getType().getCanonicalType() != + FnType->getArgType(i).getCanonicalType()) + return false; + return true; +} + +Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { + // __builtin_overload requires at least 2 arguments + if (NumArgs < 2) + return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, + SourceRange(BuiltinLoc, RParenLoc)); + + // The first argument is required to be a constant expression. It tells us + // the number of arguments to pass to each of the functions to be overloaded. + Expr **Args = reinterpret_cast(args); + Expr *NParamsExpr = Args[0]; + llvm::APSInt constEval(32); + SourceLocation ExpLoc; + if (!NParamsExpr->isIntegerConstantExpr(constEval, Context, &ExpLoc)) + return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant, + NParamsExpr->getSourceRange()); + + // Verify that the number of parameters is > 0 + unsigned NumParams = constEval.getZExtValue(); + if (NumParams == 0) + return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant, + NParamsExpr->getSourceRange()); + // Verify that we have at least 1 + NumParams arguments to the builtin. + if ((NumParams + 1) > NumArgs) + return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, + SourceRange(BuiltinLoc, RParenLoc)); + + // Figure out the return type, by matching the args to one of the functions + // listed after the parameters. + OverloadExpr *OE = 0; + for (unsigned i = NumParams + 1; i < NumArgs; ++i) { + // UsualUnaryConversions will convert the function DeclRefExpr into a + // pointer to function. + Expr *Fn = UsualUnaryConversions(Args[i]); + FunctionTypeProto *FnType = 0; + if (const PointerType *PT = Fn->getType()->getAsPointerType()) { + QualType PointeeType = PT->getPointeeType().getCanonicalType(); + FnType = dyn_cast(PointeeType); + } + + // The Expr type must be FunctionTypeProto, since FunctionTypeProto has no + // parameters, and the number of parameters must match the value passed to + // the builtin. + if (!FnType || (FnType->getNumArgs() != NumParams)) + return Diag(Fn->getExprLoc(), diag::err_overload_incorrect_fntype, + Fn->getSourceRange()); + + // Scan the parameter list for the FunctionType, checking the QualType of + // each parameter against the QualTypes of the arguments to the builtin. + // If they match, return a new OverloadExpr. + if (ExprsMatchFnType(Args+1, FnType)) { + if (OE) + return Diag(Fn->getExprLoc(), diag::err_overload_multiple_match, + OE->getFn()->getSourceRange()); + // Remember our match, and continue processing the remaining arguments + // to catch any errors. + OE = new OverloadExpr(Args, NumArgs, i, FnType->getResultType(), + BuiltinLoc, RParenLoc); + } + } + // Return the newly created OverloadExpr node, if we succeded in matching + // exactly one of the candidate functions. + if (OE) + return OE; + + // If we didn't find a matching function Expr in the __builtin_overload list + // the return an error. + std::string typeNames; + for (unsigned i = 0; i != NumParams; ++i) { + if (i != 0) typeNames += ", "; + typeNames += Args[i+1]->getType().getAsString(); + } + + return Diag(BuiltinLoc, diag::err_overload_no_match, typeNames, + SourceRange(BuiltinLoc, RParenLoc)); +} + +Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, + ExprTy *expr, TypeTy *type, + SourceLocation RPLoc) { + Expr *E = static_cast(expr); + QualType T = QualType::getFromOpaquePtr(type); + + InitBuiltinVaListType(); + + if (CheckAssignmentConstraints(Context.getBuiltinVaListType(), E->getType()) + != Compatible) + return Diag(E->getLocStart(), + diag::err_first_argument_to_va_arg_not_of_type_va_list, + E->getType().getAsString(), + E->getSourceRange()); + + // FIXME: Warn if a non-POD type is passed in. + + return new VAArgExpr(BuiltinLoc, E, T, RPLoc); +} + +bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, const char *Flavor) { + // Decode the result (notice that AST's are still created for extensions). + bool isInvalid = false; + unsigned DiagKind; + switch (ConvTy) { + default: assert(0 && "Unknown conversion type"); + case Compatible: return false; + case PointerToInt: + DiagKind = diag::ext_typecheck_convert_pointer_int; + break; + case IntToPointer: + DiagKind = diag::ext_typecheck_convert_int_pointer; + break; + case IncompatiblePointer: + DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + break; + case FunctionVoidPointer: + DiagKind = diag::ext_typecheck_convert_pointer_void_func; + break; + case CompatiblePointerDiscardsQualifiers: + DiagKind = diag::ext_typecheck_convert_discards_qualifiers; + break; + case Incompatible: + DiagKind = diag::err_typecheck_convert_incompatible; + isInvalid = true; + break; + } + + Diag(Loc, DiagKind, DstType.getAsString(), SrcType.getAsString(), Flavor, + SrcExpr->getSourceRange()); + return isInvalid; +} + diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp new file mode 100644 index 00000000000..e49a43c4728 --- /dev/null +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -0,0 +1,51 @@ +//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ expressions. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ASTContext.h" +using namespace clang; + +/// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. +Action::ExprResult +Sema::ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, ExprTy *E, + SourceLocation RParenLoc) { + CXXCastExpr::Opcode Op; + + switch (Kind) { + default: assert(0 && "Unknown C++ cast!"); + case tok::kw_const_cast: Op = CXXCastExpr::ConstCast; break; + case tok::kw_dynamic_cast: Op = CXXCastExpr::DynamicCast; break; + case tok::kw_reinterpret_cast: Op = CXXCastExpr::ReinterpretCast; break; + case tok::kw_static_cast: Op = CXXCastExpr::StaticCast; break; + } + + return new CXXCastExpr(Op, QualType::getFromOpaquePtr(Ty), (Expr*)E, OpLoc); +} + +/// ActOnCXXBoolLiteral - Parse {true,false} literals. +Action::ExprResult +Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { + assert((Kind != tok::kw_true || Kind != tok::kw_false) && + "Unknown C++ Boolean value!"); + return new CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc); +} + +/// ActOnCXXThrow - Parse throw expressions. +Action::ExprResult +Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprTy *E) { + return new CXXThrowExpr((Expr*)E, Context.VoidTy, OpLoc); +} diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp new file mode 100644 index 00000000000..4cf435c3315 --- /dev/null +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -0,0 +1,297 @@ +//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective-C expressions. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +using namespace clang; + +Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings) { + SourceLocation AtLoc = AtLocs[0]; + StringLiteral* S = static_cast(Strings[0]); + if (NumStrings > 1) { + // Concatenate objc strings. + StringLiteral* ES = static_cast(Strings[NumStrings-1]); + SourceLocation EndLoc = ES->getSourceRange().getEnd(); + unsigned Length = 0; + for (unsigned i = 0; i < NumStrings; i++) + Length += static_cast(Strings[i])->getByteLength(); + char *strBuf = new char [Length]; + char *p = strBuf; + bool isWide = false; + for (unsigned i = 0; i < NumStrings; i++) { + S = static_cast(Strings[i]); + if (S->isWide()) + isWide = true; + memcpy(p, S->getStrData(), S->getByteLength()); + p += S->getByteLength(); + delete S; + } + S = new StringLiteral(strBuf, Length, + isWide, Context.getPointerType(Context.CharTy), + AtLoc, EndLoc); + } + + if (CheckBuiltinCFStringArgument(S)) + return true; + + if (Context.getObjCConstantStringInterface().isNull()) { + // Initialize the constant string interface lazily. This assumes + // the NSConstantString interface is seen in this translation unit. + IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString"); + ScopedDecl *IFace = LookupScopedDecl(NSIdent, Decl::IDNS_Ordinary, + SourceLocation(), TUScope); + ObjCInterfaceDecl *strIFace = dyn_cast_or_null(IFace); + if (!strIFace) + return Diag(S->getLocStart(), diag::err_undef_interface, + NSIdent->getName()); + Context.setObjCConstantStringInterface(strIFace); + } + QualType t = Context.getObjCConstantStringInterface(); + t = Context.getPointerType(t); + return new ObjCStringLiteral(S, t, AtLoc); +} + +Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + TypeTy *Ty, + SourceLocation RParenLoc) { + QualType EncodedType = QualType::getFromOpaquePtr(Ty); + + QualType t = Context.getPointerType(Context.CharTy); + return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); +} + +Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + QualType t = Context.getObjCSelType(); + return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc); +} + +Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + ObjCProtocolDecl* PDecl = ObjCProtocols[ProtocolId]; + if (!PDecl) { + Diag(ProtoLoc, diag::err_undeclared_protocol, ProtocolId->getName()); + return true; + } + + QualType t = Context.getObjCProtoType(); + if (t.isNull()) + return true; + t = Context.getPointerType(t); + return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc); +} + +bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, + ObjCMethodDecl *Method) { + bool anyIncompatibleArgs = false; + + for (unsigned i = 0; i < NumArgs; i++) { + Expr *argExpr = Args[i]; + assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); + + QualType lhsType = Method->getParamDecl(i)->getType(); + QualType rhsType = argExpr->getType(); + + // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. + if (const ArrayType *ary = lhsType->getAsArrayType()) + lhsType = Context.getPointerType(ary->getElementType()); + else if (lhsType->isFunctionType()) + lhsType = Context.getPointerType(lhsType); + + AssignConvertType Result = CheckSingleAssignmentConstraints(lhsType, + argExpr); + if (Args[i] != argExpr) // The expression was converted. + Args[i] = argExpr; // Make sure we store the converted expression. + + anyIncompatibleArgs |= + DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, + argExpr, "sending"); + } + return anyIncompatibleArgs; +} + +// ActOnClassMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::ExprResult Sema::ActOnClassMessage( + Scope *S, + IdentifierInfo *receiverName, Selector Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs) +{ + assert(receiverName && "missing receiver class name"); + + Expr **ArgExprs = reinterpret_cast(Args); + ObjCInterfaceDecl* ClassDecl = 0; + if (!strcmp(receiverName->getName(), "super") && CurMethodDecl) { + ClassDecl = CurMethodDecl->getClassInterface()->getSuperClass(); + if (ClassDecl && CurMethodDecl->isInstance()) { + // Synthesize a cast to the super class. This hack allows us to loosely + // represent super without creating a special expression node. + IdentifierInfo &II = Context.Idents.get("self"); + ExprResult ReceiverExpr = ActOnIdentifierExpr(S, lbrac, II, false); + QualType superTy = Context.getObjCInterfaceType(ClassDecl); + superTy = Context.getPointerType(superTy); + ReceiverExpr = ActOnCastExpr(SourceLocation(), superTy.getAsOpaquePtr(), + SourceLocation(), ReceiverExpr.Val); + // We are really in an instance method, redirect. + return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac, + Args, NumArgs); + } + // We are sending a message to 'super' within a class method. Do nothing, + // the receiver will pass through as 'super' (how convenient:-). + } else + ClassDecl = getObjCInterfaceDecl(receiverName); + + // FIXME: can ClassDecl ever be null? + ObjCMethodDecl *Method = ClassDecl->lookupClassMethod(Sel); + QualType returnType; + + // Before we give up, check if the selector is an instance method. + if (!Method) + Method = ClassDecl->lookupInstanceMethod(Sel); + if (!Method) { + Diag(lbrac, diag::warn_method_not_found, std::string("+"), Sel.getName(), + SourceRange(lbrac, rbrac)); + returnType = Context.getObjCIdType(); + } else { + returnType = Method->getResultType(); + if (Sel.getNumArgs()) { + if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method)) + return true; + } + } + return new ObjCMessageExpr(receiverName, Sel, returnType, Method, + lbrac, rbrac, ArgExprs, NumArgs); +} + +// ActOnInstanceMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::ExprResult Sema::ActOnInstanceMessage( + ExprTy *receiver, Selector Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs) +{ + assert(receiver && "missing receiver expression"); + + Expr **ArgExprs = reinterpret_cast(Args); + Expr *RExpr = static_cast(receiver); + QualType receiverType = RExpr->getType().getCanonicalType(); + QualType returnType; + ObjCMethodDecl *Method = 0; + + // FIXME: This code is not stripping off type qualifiers! Should it? + if (receiverType == Context.getObjCIdType().getCanonicalType() || + receiverType == Context.getObjCClassType().getCanonicalType()) { + Method = InstanceMethodPool[Sel].Method; + if (!Method) + Method = FactoryMethodPool[Sel].Method; + if (!Method) { + Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(), + SourceRange(lbrac, rbrac)); + returnType = Context.getObjCIdType(); + } else { + returnType = Method->getResultType(); + if (Sel.getNumArgs()) + if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method)) + return true; + } + } else { + bool receiverIsQualId = isa(receiverType); + // FIXME (snaroff): checking in this code from Patrick. Needs to be + // revisited. how do we get the ClassDecl from the receiver expression? + if (!receiverIsQualId) + while (const PointerType *PTy = receiverType->getAsPointerType()) + receiverType = PTy->getPointeeType(); + + ObjCInterfaceDecl* ClassDecl = 0; + if (ObjCQualifiedInterfaceType *QIT = + dyn_cast(receiverType)) { + ClassDecl = QIT->getDecl(); + Method = ClassDecl->lookupInstanceMethod(Sel); + if (!Method) { + // search protocols + for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { + ObjCProtocolDecl *PDecl = QIT->getProtocols(i); + if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) + break; + } + } + if (!Method) + Diag(lbrac, diag::warn_method_not_found_in_protocol, + std::string("-"), Sel.getName(), + SourceRange(lbrac, rbrac)); + } + else if (ObjCQualifiedIdType *QIT = + dyn_cast(receiverType)) { + // search protocols + for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { + ObjCProtocolDecl *PDecl = QIT->getProtocols(i); + if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) + break; + } + if (!Method) + Diag(lbrac, diag::warn_method_not_found_in_protocol, + std::string("-"), Sel.getName(), + SourceRange(lbrac, rbrac)); + } + else { + ObjCInterfaceType *OCIReceiver =dyn_cast(receiverType); + if (OCIReceiver == 0) { + Diag(lbrac, diag::error_bad_receiver_type, + RExpr->getType().getAsString()); + return true; + } + ClassDecl = OCIReceiver->getDecl(); + // FIXME: consider using InstanceMethodPool, since it will be faster + // than the following method (which can do *many* linear searches). The + // idea is to add class info to InstanceMethodPool... + Method = ClassDecl->lookupInstanceMethod(Sel); + } + if (!Method) { + // If we have an implementation in scope, check "private" methods. + if (ClassDecl) + if (ObjCImplementationDecl *ImpDecl = + ObjCImplementations[ClassDecl->getIdentifier()]) + Method = ImpDecl->getInstanceMethod(Sel); + // If we still haven't found a method, look in the global pool. This + // behavior isn't very desirable, however we need it for GCC + // compatibility. + if (!Method) + Method = InstanceMethodPool[Sel].Method; + } + if (!Method) { + Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(), + SourceRange(lbrac, rbrac)); + returnType = Context.getObjCIdType(); + } else { + returnType = Method->getResultType(); + if (Sel.getNumArgs()) + if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method)) + return true; + } + } + return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, + ArgExprs, NumArgs); +} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp new file mode 100644 index 00000000000..14b2fdf7d0e --- /dev/null +++ b/clang/lib/Sema/SemaStmt.cpp @@ -0,0 +1,821 @@ +//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for statements. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" +#include "clang/Parse/Scope.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +Sema::StmtResult Sema::ActOnExprStmt(ExprTy *expr) { + Expr *E = static_cast(expr); + assert(E && "ActOnExprStmt(): missing expression"); + return E; +} + + +Sema::StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) { + return new NullStmt(SemiLoc); +} + +Sema::StmtResult Sema::ActOnDeclStmt(DeclTy *decl, SourceLocation StartLoc, + SourceLocation EndLoc) { + if (decl == 0) + return true; + + ScopedDecl *SD = cast(static_cast(decl)); + return new DeclStmt(SD, StartLoc, EndLoc); +} + +Action::StmtResult +Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, + StmtTy **elts, unsigned NumElts, bool isStmtExpr) { + Stmt **Elts = reinterpret_cast(elts); + // If we're in C89 mode, check that we don't have any decls after stmts. If + // so, emit an extension diagnostic. + if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) { + // Note that __extension__ can be around a decl. + unsigned i = 0; + // Skip over all declarations. + for (; i != NumElts && isa(Elts[i]); ++i) + /*empty*/; + + // We found the end of the list or a statement. Scan for another declstmt. + for (; i != NumElts && !isa(Elts[i]); ++i) + /*empty*/; + + if (i != NumElts) { + ScopedDecl *D = cast(Elts[i])->getDecl(); + Diag(D->getLocation(), diag::ext_mixed_decls_code); + } + } + // Warn about unused expressions in statements. + for (unsigned i = 0; i != NumElts; ++i) { + Expr *E = dyn_cast(Elts[i]); + if (!E) continue; + + // Warn about expressions with unused results. + if (E->hasLocalSideEffect() || E->getType()->isVoidType()) + continue; + + // The last expr in a stmt expr really is used. + if (isStmtExpr && i == NumElts-1) + continue; + + /// DiagnoseDeadExpr - This expression is side-effect free and evaluated in + /// a context where the result is unused. Emit a diagnostic to warn about + /// this. + if (const BinaryOperator *BO = dyn_cast(E)) + Diag(BO->getOperatorLoc(), diag::warn_unused_expr, + BO->getLHS()->getSourceRange(), BO->getRHS()->getSourceRange()); + else if (const UnaryOperator *UO = dyn_cast(E)) + Diag(UO->getOperatorLoc(), diag::warn_unused_expr, + UO->getSubExpr()->getSourceRange()); + else + Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange()); + } + + return new CompoundStmt(Elts, NumElts, L, R); +} + +Action::StmtResult +Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval, + SourceLocation DotDotDotLoc, ExprTy *rhsval, + SourceLocation ColonLoc, StmtTy *subStmt) { + Stmt *SubStmt = static_cast(subStmt); + Expr *LHSVal = ((Expr *)lhsval), *RHSVal = ((Expr *)rhsval); + assert((LHSVal != 0) && "missing expression in case statement"); + + SourceLocation ExpLoc; + // C99 6.8.4.2p3: The expression shall be an integer constant. + if (!LHSVal->isIntegerConstantExpr(Context, &ExpLoc)) { + Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, + LHSVal->getSourceRange()); + return SubStmt; + } + + // GCC extension: The expression shall be an integer constant. + if (RHSVal && !RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) { + Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr, + RHSVal->getSourceRange()); + RHSVal = 0; // Recover by just forgetting about it. + } + + if (SwitchStack.empty()) { + Diag(CaseLoc, diag::err_case_not_in_switch); + return SubStmt; + } + + CaseStmt *CS = new CaseStmt(LHSVal, RHSVal, SubStmt, CaseLoc); + SwitchStack.back()->addSwitchCase(CS); + return CS; +} + +Action::StmtResult +Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, + StmtTy *subStmt, Scope *CurScope) { + Stmt *SubStmt = static_cast(subStmt); + + if (SwitchStack.empty()) { + Diag(DefaultLoc, diag::err_default_not_in_switch); + return SubStmt; + } + + DefaultStmt *DS = new DefaultStmt(DefaultLoc, SubStmt); + SwitchStack.back()->addSwitchCase(DS); + + return DS; +} + +Action::StmtResult +Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation ColonLoc, StmtTy *subStmt) { + Stmt *SubStmt = static_cast(subStmt); + // Look up the record for this label identifier. + LabelStmt *&LabelDecl = LabelMap[II]; + + // If not forward referenced or defined already, just create a new LabelStmt. + if (LabelDecl == 0) + return LabelDecl = new LabelStmt(IdentLoc, II, SubStmt); + + assert(LabelDecl->getID() == II && "Label mismatch!"); + + // Otherwise, this label was either forward reference or multiply defined. If + // multiply defined, reject it now. + if (LabelDecl->getSubStmt()) { + Diag(IdentLoc, diag::err_redefinition_of_label, LabelDecl->getName()); + Diag(LabelDecl->getIdentLoc(), diag::err_previous_definition); + return SubStmt; + } + + // Otherwise, this label was forward declared, and we just found its real + // definition. Fill in the forward definition and return it. + LabelDecl->setIdentLoc(IdentLoc); + LabelDecl->setSubStmt(SubStmt); + return LabelDecl; +} + +Action::StmtResult +Sema::ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal, + StmtTy *ThenVal, SourceLocation ElseLoc, + StmtTy *ElseVal) { + Expr *condExpr = (Expr *)CondVal; + Stmt *thenStmt = (Stmt *)ThenVal; + + assert(condExpr && "ActOnIfStmt(): missing expression"); + + DefaultFunctionArrayConversion(condExpr); + QualType condType = condExpr->getType(); + + if (!condType->isScalarType()) // C99 6.8.4.1p1 + return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar, + condType.getAsString(), condExpr->getSourceRange()); + + // Warn if the if block has a null body without an else value. + // this helps prevent bugs due to typos, such as + // if (condition); + // do_stuff(); + if (!ElseVal) { + if (NullStmt* stmt = dyn_cast(thenStmt)) + Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); + } + + return new IfStmt(IfLoc, condExpr, thenStmt, (Stmt*)ElseVal); +} + +Action::StmtResult +Sema::ActOnStartOfSwitchStmt(ExprTy *cond) { + Expr *Cond = static_cast(cond); + + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. + UsualUnaryConversions(Cond); + + SwitchStmt *SS = new SwitchStmt(Cond); + SwitchStack.push_back(SS); + return SS; +} + +/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have +/// the specified width and sign. If an overflow occurs, detect it and emit +/// the specified diagnostic. +void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, + unsigned DiagID) { + // Perform a conversion to the promoted condition type if needed. + if (NewWidth > Val.getBitWidth()) { + // If this is an extension, just do it. + llvm::APSInt OldVal(Val); + Val.extend(NewWidth); + + // If the input was signed and negative and the output is unsigned, + // warn. + if (!NewSign && OldVal.isSigned() && OldVal.isNegative()) + Diag(Loc, DiagID, OldVal.toString(), Val.toString()); + + Val.setIsSigned(NewSign); + } else if (NewWidth < Val.getBitWidth()) { + // If this is a truncation, check for overflow. + llvm::APSInt ConvVal(Val); + ConvVal.trunc(NewWidth); + ConvVal.setIsSigned(NewSign); + ConvVal.extend(Val.getBitWidth()); + ConvVal.setIsSigned(Val.isSigned()); + if (ConvVal != Val) + Diag(Loc, DiagID, Val.toString(), ConvVal.toString()); + + // Regardless of whether a diagnostic was emitted, really do the + // truncation. + Val.trunc(NewWidth); + Val.setIsSigned(NewSign); + } else if (NewSign != Val.isSigned()) { + // Convert the sign to match the sign of the condition. This can cause + // overflow as well: unsigned(INTMIN) + llvm::APSInt OldVal(Val); + Val.setIsSigned(NewSign); + + if (Val.isNegative()) // Sign bit changes meaning. + Diag(Loc, DiagID, OldVal.toString(), Val.toString()); + } +} + +namespace { + struct CaseCompareFunctor { + bool operator()(const std::pair &LHS, + const llvm::APSInt &RHS) { + return LHS.first < RHS; + } + bool operator()(const std::pair &LHS, + const std::pair &RHS) { + return LHS.first < RHS.first; + } + bool operator()(const llvm::APSInt &LHS, + const std::pair &RHS) { + return LHS < RHS.first; + } + }; +} + +/// CmpCaseVals - Comparison predicate for sorting case values. +/// +static bool CmpCaseVals(const std::pair& lhs, + const std::pair& rhs) { + if (lhs.first < rhs.first) + return true; + + if (lhs.first == rhs.first && + lhs.second->getCaseLoc().getRawEncoding() + < rhs.second->getCaseLoc().getRawEncoding()) + return true; + return false; +} + +Action::StmtResult +Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, + ExprTy *Body) { + Stmt *BodyStmt = (Stmt*)Body; + + SwitchStmt *SS = SwitchStack.back(); + assert(SS == (SwitchStmt*)Switch && "switch stack missing push/pop!"); + + SS->setBody(BodyStmt, SwitchLoc); + SwitchStack.pop_back(); + + Expr *CondExpr = SS->getCond(); + QualType CondType = CondExpr->getType(); + + if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 + Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer, + CondType.getAsString(), CondExpr->getSourceRange()); + return true; + } + + // Get the bitwidth of the switched-on value before promotions. We must + // convert the integer case values to this width before comparison. + unsigned CondWidth = static_cast(Context.getTypeSize(CondType)); + bool CondIsSigned = CondType->isSignedIntegerType(); + + // Accumulate all of the case values in a vector so that we can sort them + // and detect duplicates. This vector contains the APInt for the case after + // it has been converted to the condition type. + typedef llvm::SmallVector, 64> CaseValsTy; + CaseValsTy CaseVals; + + // Keep track of any GNU case ranges we see. The APSInt is the low value. + std::vector > CaseRanges; + + DefaultStmt *TheDefaultStmt = 0; + + bool CaseListIsErroneous = false; + + for (SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + + if (DefaultStmt *DS = dyn_cast(SC)) { + if (TheDefaultStmt) { + Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined); + Diag(TheDefaultStmt->getDefaultLoc(), diag::err_first_label); + + // FIXME: Remove the default statement from the switch block so that + // we'll return a valid AST. This requires recursing down the + // AST and finding it, not something we are set up to do right now. For + // now, just lop the entire switch stmt out of the AST. + CaseListIsErroneous = true; + } + TheDefaultStmt = DS; + + } else { + CaseStmt *CS = cast(SC); + + // We already verified that the expression has a i-c-e value (C99 + // 6.8.4.2p3) - get that value now. + llvm::APSInt LoVal(32); + Expr *Lo = CS->getLHS(); + Lo->isIntegerConstantExpr(LoVal, Context); + + // Convert the value to the same width/sign as the condition. + ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, + CS->getLHS()->getLocStart(), + diag::warn_case_value_overflow); + + // If the LHS is not the same type as the condition, insert an implicit + // cast. + ImpCastExprToType(Lo, CondType); + CS->setLHS(Lo); + + // If this is a case range, remember it in CaseRanges, otherwise CaseVals. + if (CS->getRHS()) + CaseRanges.push_back(std::make_pair(LoVal, CS)); + else + CaseVals.push_back(std::make_pair(LoVal, CS)); + } + } + + // Sort all the scalar case values so we can easily detect duplicates. + std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); + + if (!CaseVals.empty()) { + for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { + if (CaseVals[i].first == CaseVals[i+1].first) { + // If we have a duplicate, report it. + Diag(CaseVals[i+1].second->getLHS()->getLocStart(), + diag::err_duplicate_case, CaseVals[i].first.toString()); + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case_prev); + // FIXME: We really want to remove the bogus case stmt from the substmt, + // but we have no way to do this right now. + CaseListIsErroneous = true; + } + } + } + + // Detect duplicate case ranges, which usually don't exist at all in the first + // place. + if (!CaseRanges.empty()) { + // Sort all the case ranges by their low value so we can easily detect + // overlaps between ranges. + std::stable_sort(CaseRanges.begin(), CaseRanges.end()); + + // Scan the ranges, computing the high values and removing empty ranges. + std::vector HiVals; + for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + CaseStmt *CR = CaseRanges[i].second; + llvm::APSInt HiVal(32); + Expr *Hi = CR->getRHS(); + Hi->isIntegerConstantExpr(HiVal, Context); + + // Convert the value to the same width/sign as the condition. + ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, + CR->getRHS()->getLocStart(), + diag::warn_case_value_overflow); + + // If the LHS is not the same type as the condition, insert an implicit + // cast. + ImpCastExprToType(Hi, CondType); + CR->setRHS(Hi); + + // If the low value is bigger than the high value, the case is empty. + if (CaseRanges[i].first > HiVal) { + Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range, + SourceRange(CR->getLHS()->getLocStart(), + CR->getRHS()->getLocEnd())); + CaseRanges.erase(CaseRanges.begin()+i); + --i, --e; + continue; + } + HiVals.push_back(HiVal); + } + + // Rescan the ranges, looking for overlap with singleton values and other + // ranges. Since the range list is sorted, we only need to compare case + // ranges with their neighbors. + for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + llvm::APSInt &CRLo = CaseRanges[i].first; + llvm::APSInt &CRHi = HiVals[i]; + CaseStmt *CR = CaseRanges[i].second; + + // Check to see whether the case range overlaps with any singleton cases. + CaseStmt *OverlapStmt = 0; + llvm::APSInt OverlapVal(32); + + // Find the smallest value >= the lower bound. If I is in the case range, + // then we have overlap. + CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(), + CaseVals.end(), CRLo, + CaseCompareFunctor()); + if (I != CaseVals.end() && I->first < CRHi) { + OverlapVal = I->first; // Found overlap with scalar. + OverlapStmt = I->second; + } + + // Find the smallest value bigger than the upper bound. + I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor()); + if (I != CaseVals.begin() && (I-1)->first >= CRLo) { + OverlapVal = (I-1)->first; // Found overlap with scalar. + OverlapStmt = (I-1)->second; + } + + // Check to see if this case stmt overlaps with the subsequent case range. + if (i && CRLo <= HiVals[i-1]) { + OverlapVal = HiVals[i-1]; // Found overlap with range. + OverlapStmt = CaseRanges[i-1].second; + } + + if (OverlapStmt) { + // If we have a duplicate, report it. + Diag(CR->getLHS()->getLocStart(), + diag::err_duplicate_case, OverlapVal.toString()); + Diag(OverlapStmt->getLHS()->getLocStart(), + diag::err_duplicate_case_prev); + // FIXME: We really want to remove the bogus case stmt from the substmt, + // but we have no way to do this right now. + CaseListIsErroneous = true; + } + } + } + + // FIXME: If the case list was broken is some way, we don't have a good system + // to patch it up. Instead, just return the whole substmt as broken. + if (CaseListIsErroneous) + return true; + + return SS; +} + +Action::StmtResult +Sema::ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) { + Expr *condExpr = (Expr *)Cond; + assert(condExpr && "ActOnWhileStmt(): missing expression"); + + DefaultFunctionArrayConversion(condExpr); + QualType condType = condExpr->getType(); + + if (!condType->isScalarType()) // C99 6.8.5p2 + return Diag(WhileLoc, diag::err_typecheck_statement_requires_scalar, + condType.getAsString(), condExpr->getSourceRange()); + + return new WhileStmt(condExpr, (Stmt*)Body, WhileLoc); +} + +Action::StmtResult +Sema::ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body, + SourceLocation WhileLoc, ExprTy *Cond) { + Expr *condExpr = (Expr *)Cond; + assert(condExpr && "ActOnDoStmt(): missing expression"); + + DefaultFunctionArrayConversion(condExpr); + QualType condType = condExpr->getType(); + + if (!condType->isScalarType()) // C99 6.8.5p2 + return Diag(DoLoc, diag::err_typecheck_statement_requires_scalar, + condType.getAsString(), condExpr->getSourceRange()); + + return new DoStmt((Stmt*)Body, condExpr, DoLoc); +} + +Action::StmtResult +Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, + StmtTy *first, ExprTy *second, ExprTy *third, + SourceLocation RParenLoc, StmtTy *body) { + Stmt *First = static_cast(first); + Expr *Second = static_cast(second); + Expr *Third = static_cast(third); + Stmt *Body = static_cast(body); + + if (DeclStmt *DS = dyn_cast_or_null(First)) { + // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare + // identifiers for objects having storage class 'auto' or 'register'. + for (ScopedDecl *D = DS->getDecl(); D; D = D->getNextDeclarator()) { + BlockVarDecl *BVD = dyn_cast(D); + if (BVD && !BVD->hasLocalStorage()) + BVD = 0; + if (BVD == 0) + Diag(dyn_cast(D)->getLocation(), + diag::err_non_variable_decl_in_for); + // FIXME: mark decl erroneous! + } + } + if (Second) { + DefaultFunctionArrayConversion(Second); + QualType SecondType = Second->getType(); + + if (!SecondType->isScalarType()) // C99 6.8.5p2 + return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar, + SecondType.getAsString(), Second->getSourceRange()); + } + return new ForStmt(First, Second, Third, Body, ForLoc); +} + +Action::StmtResult +Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtTy *first, ExprTy *second, + SourceLocation RParenLoc, StmtTy *body) { + Stmt *First = static_cast(first); + Expr *Second = static_cast(second); + Stmt *Body = static_cast(body); + if (First) { + QualType FirstType; + if (DeclStmt *DS = dyn_cast(First)) { + FirstType = cast(DS->getDecl())->getType(); + // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare + // identifiers for objects having storage class 'auto' or 'register'. + ScopedDecl *D = DS->getDecl(); + BlockVarDecl *BVD = cast(D); + if (!BVD->hasLocalStorage()) + return Diag(BVD->getLocation(), diag::err_non_variable_decl_in_for); + if (D->getNextDeclarator()) + return Diag(D->getLocation(), diag::err_toomany_element_decls); + } + else + FirstType = static_cast(first)->getType(); + if (!isObjCObjectPointerType(FirstType)) + Diag(ForLoc, diag::err_selector_element_type, + FirstType.getAsString(), First->getSourceRange()); + } + if (Second) { + DefaultFunctionArrayConversion(Second); + QualType SecondType = Second->getType(); + if (!isObjCObjectPointerType(SecondType)) + Diag(ForLoc, diag::err_collection_expr_type, + SecondType.getAsString(), Second->getSourceRange()); + } + return new ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc); +} + +Action::StmtResult +Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, + IdentifierInfo *LabelII) { + // Look up the record for this label identifier. + LabelStmt *&LabelDecl = LabelMap[LabelII]; + + // If we haven't seen this label yet, create a forward reference. + if (LabelDecl == 0) + LabelDecl = new LabelStmt(LabelLoc, LabelII, 0); + + return new GotoStmt(LabelDecl, GotoLoc, LabelLoc); +} + +Action::StmtResult +Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc,SourceLocation StarLoc, + ExprTy *DestExp) { + // FIXME: Verify that the operand is convertible to void*. + + return new IndirectGotoStmt((Expr*)DestExp); +} + +Action::StmtResult +Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { + Scope *S = CurScope->getContinueParent(); + if (!S) { + // C99 6.8.6.2p1: A break shall appear only in or as a loop body. + Diag(ContinueLoc, diag::err_continue_not_in_loop); + return true; + } + + return new ContinueStmt(ContinueLoc); +} + +Action::StmtResult +Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { + Scope *S = CurScope->getBreakParent(); + if (!S) { + // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body. + Diag(BreakLoc, diag::err_break_not_in_loop_or_switch); + return true; + } + + return new BreakStmt(BreakLoc); +} + + +Action::StmtResult +Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) { + Expr *RetValExp = static_cast(rex); + QualType FnRetType = CurFunctionDecl ? CurFunctionDecl->getResultType() : + CurMethodDecl->getResultType(); + + if (FnRetType->isVoidType()) { + if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns) + Diag(ReturnLoc, diag::ext_return_has_expr, + (CurFunctionDecl ? CurFunctionDecl->getIdentifier()->getName() : + CurMethodDecl->getSelector().getName()), + RetValExp->getSourceRange()); + return new ReturnStmt(ReturnLoc, RetValExp); + } else { + if (!RetValExp) { + const char *funcName = CurFunctionDecl ? + CurFunctionDecl->getIdentifier()->getName() : + CurMethodDecl->getSelector().getName().c_str(); + if (getLangOptions().C99) // C99 6.8.6.4p1 (ext_ since GCC warns) + Diag(ReturnLoc, diag::ext_return_missing_expr, funcName); + else // C90 6.6.6.4p4 + Diag(ReturnLoc, diag::warn_return_missing_expr, funcName); + return new ReturnStmt(ReturnLoc, (Expr*)0); + } + } + // we have a non-void function with an expression, continue checking + QualType RetValType = RetValExp->getType(); + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + AssignConvertType ConvTy = CheckSingleAssignmentConstraints(FnRetType, + RetValExp); + if (DiagnoseAssignmentResult(ConvTy, ReturnLoc, FnRetType, + RetValType, RetValExp, "returning")) + return true; + + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + + return new ReturnStmt(ReturnLoc, (Expr*)RetValExp); +} + +Sema::StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + std::string *Names, + ExprTy **Constraints, + ExprTy **Exprs, + ExprTy *AsmString, + unsigned NumClobbers, + ExprTy **Clobbers, + SourceLocation RParenLoc) { + Expr *E = (Expr *)AsmString; + + for (unsigned i = 0; i < NumOutputs; i++) { + StringLiteral *Literal = cast((Expr *)Constraints[i]); + assert(!Literal->isWide() && + "Output constraint strings should not be wide!"); + + std::string OutputConstraint(Literal->getStrData(), + Literal->getByteLength()); + + TargetInfo::ConstraintInfo info; + if (!Context.Target.validateOutputConstraint(OutputConstraint.c_str(), + info)) { + // FIXME: We currently leak memory here. + Diag(Literal->getLocStart(), + diag::err_invalid_output_constraint_in_asm); + return true; + } + + // Check that the output exprs are valid lvalues. + Expr *OutputExpr = (Expr *)Exprs[i]; + Expr::isLvalueResult Result = OutputExpr->isLvalue(); + if (Result != Expr::LV_Valid) { + ParenExpr *PE = cast(OutputExpr); + + Diag(PE->getSubExpr()->getLocStart(), + diag::err_invalid_lvalue_in_asm_output, + PE->getSubExpr()->getSourceRange()); + + // FIXME: We currently leak memory here. + return true; + } + } + + for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { + StringLiteral *Literal = cast((Expr *)Constraints[i]); + assert(!Literal->isWide() && + "Output constraint strings should not be wide!"); + + std::string InputConstraint(Literal->getStrData(), + Literal->getByteLength()); + + TargetInfo::ConstraintInfo info; + if (!Context.Target.validateInputConstraint(InputConstraint.c_str(), + NumOutputs, + info)) { + // FIXME: We currently leak memory here. + Diag(Literal->getLocStart(), + diag::err_invalid_input_constraint_in_asm); + return true; + } + + // Check that the input exprs aren't of type void. + Expr *InputExpr = (Expr *)Exprs[i]; + if (InputExpr->getType()->isVoidType()) { + ParenExpr *PE = cast(InputExpr); + + Diag(PE->getSubExpr()->getLocStart(), + diag::err_invalid_type_in_asm_input, + PE->getType().getAsString(), + PE->getSubExpr()->getSourceRange()); + + // FIXME: We currently leak memory here. + return true; + } + } + + // Check that the clobbers are valid. + for (unsigned i = 0; i < NumClobbers; i++) { + StringLiteral *Literal = cast((Expr *)Clobbers[i]); + assert(!Literal->isWide() && "Clobber strings should not be wide!"); + + llvm::SmallString<16> Clobber(Literal->getStrData(), + Literal->getStrData() + + Literal->getByteLength()); + + if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) { + Diag(Literal->getLocStart(), + diag::err_unknown_register_name_in_asm, + Clobber.c_str()); + + // FIXME: We currently leak memory here. + return true; + } + } + + return new AsmStmt(AsmLoc, + IsSimple, + IsVolatile, + NumOutputs, + NumInputs, + Names, + reinterpret_cast(Constraints), + reinterpret_cast(Exprs), + cast(E), + NumClobbers, + reinterpret_cast(Clobbers), + RParenLoc); +} + +Action::StmtResult +Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParen, StmtTy *Parm, + StmtTy *Body, StmtTy *CatchList) { + ObjCAtCatchStmt *CS = new ObjCAtCatchStmt(AtLoc, RParen, + static_cast(Parm), static_cast(Body), + static_cast(CatchList)); + return CatchList ? CatchList : CS; +} + +Action::StmtResult +Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtTy *Body) { + ObjCAtFinallyStmt *FS = new ObjCAtFinallyStmt(AtLoc, + static_cast(Body)); + return FS; +} + +Action::StmtResult +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, + StmtTy *Try, StmtTy *Catch, StmtTy *Finally) { + ObjCAtTryStmt *TS = new ObjCAtTryStmt(AtLoc, static_cast(Try), + static_cast(Catch), + static_cast(Finally)); + return TS; +} + +Action::StmtResult +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, StmtTy *Throw) { + ObjCAtThrowStmt *TS = new ObjCAtThrowStmt(AtLoc, static_cast(Throw)); + return TS; +} + +Action::StmtResult +Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprTy *SynchExpr, + StmtTy *SynchBody) { + ObjCAtSynchronizedStmt *SS = new ObjCAtSynchronizedStmt(AtLoc, + static_cast(SynchExpr), static_cast(SynchBody)); + return SS; +} + + diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp new file mode 100644 index 00000000000..f717b4139a5 --- /dev/null +++ b/clang/lib/Sema/SemaType.cpp @@ -0,0 +1,498 @@ +//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements type-related semantic analysis. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/LangOptions.h" +using namespace clang; + +/// ConvertDeclSpecToType - Convert the specified declspec to the appropriate +/// type object. This returns null on error. +QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) { + // FIXME: Should move the logic from DeclSpec::Finish to here for validity + // checking. + QualType Result; + + switch (DS.getTypeSpecType()) { + default: return QualType(); // FIXME: Handle unimp cases! + case DeclSpec::TST_void: return Context.VoidTy; + case DeclSpec::TST_char: + if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) + Result = Context.CharTy; + else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) + Result = Context.SignedCharTy; + else { + assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && + "Unknown TSS value"); + Result = Context.UnsignedCharTy; + } + break; + case DeclSpec::TST_unspecified: // Unspecific typespec defaults to int. + case DeclSpec::TST_int: { + if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { + switch (DS.getTypeSpecWidth()) { + case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; + case DeclSpec::TSW_short: Result = Context.ShortTy; break; + case DeclSpec::TSW_long: Result = Context.LongTy; break; + case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; + } + } else { + switch (DS.getTypeSpecWidth()) { + case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; + case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; + case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; + case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; + } + } + break; + } + case DeclSpec::TST_float: Result = Context.FloatTy; break; + case DeclSpec::TST_double: + if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) + Result = Context.LongDoubleTy; + else + Result = Context.DoubleTy; + break; + case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool + case DeclSpec::TST_decimal32: // _Decimal32 + case DeclSpec::TST_decimal64: // _Decimal64 + case DeclSpec::TST_decimal128: // _Decimal128 + assert(0 && "FIXME: GNU decimal extensions not supported yet!"); + case DeclSpec::TST_enum: + case DeclSpec::TST_union: + case DeclSpec::TST_struct: { + Decl *D = static_cast(DS.getTypeRep()); + assert(D && "Didn't get a decl for a enum/union/struct?"); + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && + DS.getTypeSpecSign() == 0 && + "Can't handle qualifiers on typedef names yet!"); + // TypeQuals handled by caller. + Result = Context.getTagDeclType(cast(D)); + break; + } + case DeclSpec::TST_typedef: { + Decl *D = static_cast(DS.getTypeRep()); + assert(D && "Didn't get a decl for a typedef?"); + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && + DS.getTypeSpecSign() == 0 && + "Can't handle qualifiers on typedef names yet!"); + // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so + // we have this "hack" for now... + if (ObjCInterfaceDecl *ObjCIntDecl = dyn_cast(D)) { + if (DS.getProtocolQualifiers() == 0) { + Result = Context.getObjCInterfaceType(ObjCIntDecl); + break; + } + + Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0]; + Result = Context.getObjCQualifiedInterfaceType(ObjCIntDecl, + reinterpret_cast(PPDecl), + DS.getNumProtocolQualifiers()); + break; + } + else if (TypedefDecl *typeDecl = dyn_cast(D)) { + if (Context.getObjCIdType() == Context.getTypedefType(typeDecl) + && DS.getProtocolQualifiers()) { + // id + Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0]; + Result = Context.getObjCQualifiedIdType(typeDecl->getUnderlyingType(), + reinterpret_cast(PPDecl), + DS.getNumProtocolQualifiers()); + break; + } + } + // TypeQuals handled by caller. + Result = Context.getTypedefType(cast(D)); + break; + } + case DeclSpec::TST_typeofType: + Result = QualType::getFromOpaquePtr(DS.getTypeRep()); + assert(!Result.isNull() && "Didn't get a type for typeof?"); + // TypeQuals handled by caller. + Result = Context.getTypeOfType(Result); + break; + case DeclSpec::TST_typeofExpr: { + Expr *E = static_cast(DS.getTypeRep()); + assert(E && "Didn't get an expression for typeof?"); + // TypeQuals handled by caller. + Result = Context.getTypeOfExpr(E); + break; + } + } + + // Handle complex types. + if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) + Result = Context.getComplexType(Result); + + assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && + "FIXME: imaginary types not supported yet!"); + + // See if there are any attributes on the declspec that apply to the type (as + // opposed to the decl). + if (AttributeList *AL = DS.getAttributes()) + DS.SetAttributes(ProcessTypeAttributes(Result, AL)); + + return Result; +} + +/// GetTypeForDeclarator - Convert the type for the specified declarator to Type +/// instances. +QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { + // long long is a C99 feature. + if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && + D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) + Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); + + QualType T = ConvertDeclSpecToType(D.getDeclSpec()); + + // Apply const/volatile/restrict qualifiers to T. + T = T.getQualifiedType(D.getDeclSpec().getTypeQualifiers()); + + // Walk the DeclTypeInfo, building the recursive type as we go. DeclTypeInfos + // are ordered from the identifier out, which is opposite of what we want :). + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); + switch (DeclType.Kind) { + default: assert(0 && "Unknown decltype!"); + case DeclaratorChunk::Pointer: + if (T->isReferenceType()) { + // C++ 8.3.2p4: There shall be no ... pointers to references ... + Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference, + D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + D.setInvalidType(true); + T = Context.IntTy; + } + + // Apply the pointer typequals to the pointer object. + T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals); + + // See if there are any attributes on the pointer that apply to it. + if (AttributeList *AL = DeclType.Ptr.AttrList) + DeclType.Ptr.AttrList = ProcessTypeAttributes(T, AL); + + break; + case DeclaratorChunk::Reference: + if (const ReferenceType *RT = T->getAsReferenceType()) { + // C++ 8.3.2p4: There shall be no references to references. + Diag(D.getIdentifierLoc(), + diag::err_illegal_decl_reference_to_reference, + D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + D.setInvalidType(true); + T = RT->getReferenceeType(); + } + + T = Context.getReferenceType(T); + + // FIXME: Handle Ref.Restrict! + + // See if there are any attributes on the pointer that apply to it. + if (AttributeList *AL = DeclType.Ref.AttrList) + DeclType.Ref.AttrList = ProcessTypeAttributes(T, AL); + break; + case DeclaratorChunk::Array: { + const DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; + Expr *ArraySize = static_cast(ATI.NumElts); + ArrayType::ArraySizeModifier ASM; + if (ATI.isStar) + ASM = ArrayType::Star; + else if (ATI.hasStatic) + ASM = ArrayType::Static; + else + ASM = ArrayType::Normal; + + // C99 6.7.5.2p1: If the element type is an incomplete or function type, + // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) + if (T->isIncompleteType()) { + Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_incomplete_type, + T.getAsString()); + T = Context.IntTy; + D.setInvalidType(true); + } else if (T->isFunctionType()) { + Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions, + D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + T = Context.getPointerType(T); + D.setInvalidType(true); + } else if (const ReferenceType *RT = T->getAsReferenceType()) { + // C++ 8.3.2p4: There shall be no ... arrays of references ... + Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references, + D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + T = RT->getReferenceeType(); + D.setInvalidType(true); + } else if (const RecordType *EltTy = T->getAsRecordType()) { + // If the element type is a struct or union that contains a variadic + // array, reject it: C99 6.7.2.1p2. + if (EltTy->getDecl()->hasFlexibleArrayMember()) { + Diag(DeclType.Loc, diag::err_flexible_array_in_array, + T.getAsString()); + T = Context.IntTy; + D.setInvalidType(true); + } + } + // C99 6.7.5.2p1: The size expression shall have integer type. + if (ArraySize && !ArraySize->getType()->isIntegerType()) { + Diag(ArraySize->getLocStart(), diag::err_array_size_non_int, + ArraySize->getType().getAsString(), ArraySize->getSourceRange()); + D.setInvalidType(true); + } + llvm::APSInt ConstVal(32); + // If no expression was provided, we consider it a VLA. + if (!ArraySize) { + T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals); + } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context)) { + T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals); + } else { + // C99 6.7.5.2p1: If the expression is a constant expression, it shall + // have a value greater than zero. + if (ConstVal.isSigned()) { + if (ConstVal.isNegative()) { + Diag(ArraySize->getLocStart(), + diag::err_typecheck_negative_array_size, + ArraySize->getSourceRange()); + D.setInvalidType(true); + } else if (ConstVal == 0) { + // GCC accepts zero sized static arrays. + Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size, + ArraySize->getSourceRange()); + } + } + T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals); + } + // If this is not C99, extwarn about VLA's and C99 array size modifiers. + if (!getLangOptions().C99 && + (ASM != ArrayType::Normal || + (ArraySize && !ArraySize->isIntegerConstantExpr(Context)))) + Diag(D.getIdentifierLoc(), diag::ext_vla); + break; + } + case DeclaratorChunk::Function: + // If the function declarator has a prototype (i.e. it is not () and + // does not have a K&R-style identifier list), then the arguments are part + // of the type, otherwise the argument list is (). + const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + + // C99 6.7.5.3p1: The return type may not be a function or array type. + if (T->isArrayType() || T->isFunctionType()) { + Diag(DeclType.Loc, diag::err_func_returning_array_function, + T.getAsString()); + T = Context.IntTy; + D.setInvalidType(true); + } + + if (!FTI.hasPrototype) { + // Simple void foo(), where the incoming T is the result type. + T = Context.getFunctionTypeNoProto(T); + + // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. + if (FTI.NumArgs != 0) + Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + + } else { + // Otherwise, we have a function with an argument list that is + // potentially variadic. + llvm::SmallVector ArgTys; + + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + QualType ArgTy = QualType::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo); + assert(!ArgTy.isNull() && "Couldn't parse type?"); + // + // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). + // This matches the conversion that is done in + // Sema::ActOnParamDeclarator(). Without this conversion, the + // argument type in the function prototype *will not* match the + // type in ParmVarDecl (which makes the code generator unhappy). + // + // FIXME: We still apparently need the conversion in + // Sema::ParseParamDeclarator(). This doesn't make any sense, since + // it should be driving off the type being created here. + // + // FIXME: If a source translation tool needs to see the original type, + // then we need to consider storing both types somewhere... + // + if (const ArrayType *AT = ArgTy->getAsArrayType()) { + // int x[restrict 4] -> int *restrict + ArgTy = Context.getPointerType(AT->getElementType()); + ArgTy = ArgTy.getQualifiedType(AT->getIndexTypeQualifier()); + } else if (ArgTy->isFunctionType()) + ArgTy = Context.getPointerType(ArgTy); + // Look for 'void'. void is allowed only as a single argument to a + // function with no other parameters (C99 6.7.5.3p10). We record + // int(void) as a FunctionTypeProto with an empty argument list. + else if (ArgTy->isVoidType()) { + // If this is something like 'float(int, void)', reject it. 'void' + // is an incomplete type (C99 6.2.5p19) and function decls cannot + // have arguments of incomplete type. + if (FTI.NumArgs != 1 || FTI.isVariadic) { + Diag(DeclType.Loc, diag::err_void_only_param); + ArgTy = Context.IntTy; + FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr(); + } else if (FTI.ArgInfo[i].Ident) { + // Reject, but continue to parse 'int(void abc)'. + Diag(FTI.ArgInfo[i].IdentLoc, + diag::err_param_with_void_type); + ArgTy = Context.IntTy; + FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr(); + } else { + // Reject, but continue to parse 'float(const void)'. + if (ArgTy.getCVRQualifiers()) + Diag(DeclType.Loc, diag::err_void_param_qualified); + + // Do not add 'void' to the ArgTys list. + break; + } + } + + ArgTys.push_back(ArgTy); + } + T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), + FTI.isVariadic); + } + break; + } + } + + return T; +} + +/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition +/// declarator +QualType Sema::ObjCGetTypeForMethodDefinition(DeclTy *D) { + ObjCMethodDecl *MDecl = dyn_cast(static_cast(D)); + QualType T = MDecl->getResultType(); + llvm::SmallVector ArgTys; + + // Add the first two invisible argument types for self and _cmd. + if (MDecl->isInstance()) { + QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface()); + selfTy = Context.getPointerType(selfTy); + ArgTys.push_back(selfTy); + } + else + ArgTys.push_back(Context.getObjCIdType()); + ArgTys.push_back(Context.getObjCSelType()); + + for (int i = 0; i < MDecl->getNumParams(); i++) { + ParmVarDecl *PDecl = MDecl->getParamDecl(i); + QualType ArgTy = PDecl->getType(); + assert(!ArgTy.isNull() && "Couldn't parse type?"); + // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). + // This matches the conversion that is done in + // Sema::ParseParamDeclarator(). + if (const ArrayType *AT = ArgTy->getAsArrayType()) + ArgTy = Context.getPointerType(AT->getElementType()); + else if (ArgTy->isFunctionType()) + ArgTy = Context.getPointerType(ArgTy); + ArgTys.push_back(ArgTy); + } + T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), + MDecl->isVariadic()); + return T; +} + +Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { + // C99 6.7.6: Type names have no identifier. This is already validated by + // the parser. + assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); + + QualType T = GetTypeForDeclarator(D, S); + + assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + + // In this context, we *do not* check D.getInvalidType(). If the declarator + // type was invalid, GetTypeForDeclarator() still returns a "valid" type, + // though it will not reflect the user specified type. + return T.getAsOpaquePtr(); +} + +// Called from Parser::ParseParenDeclarator(). +Sema::TypeResult Sema::ActOnParamDeclaratorType(Scope *S, Declarator &D) { + // Note: parameters have identifiers, but we don't care about them here, we + // just want the type converted. + QualType T = GetTypeForDeclarator(D, S); + + assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + + // In this context, we *do not* check D.getInvalidType(). If the declarator + // type was invalid, GetTypeForDeclarator() still returns a "valid" type, + // though it will not reflect the user specified type. + return T.getAsOpaquePtr(); +} + +AttributeList *Sema::ProcessTypeAttributes(QualType &Result, AttributeList *AL){ + // Scan through and apply attributes to this type where it makes sense. Some + // attributes (such as __address_space__, __vector_size__, etc) apply to the + // type, but others can be present in the type specifiers even though they + // apply to the decl. Here we apply and delete attributes that apply to the + // type and leave the others alone. + llvm::SmallVector LeftOverAttrs; + while (AL) { + // Unlink this attribute from the chain, so we can process it independently. + AttributeList *ThisAttr = AL; + AL = AL->getNext(); + ThisAttr->setNext(0); + + // If this is an attribute we can handle, do so now, otherwise, add it to + // the LeftOverAttrs list for rechaining. + switch (ThisAttr->getKind()) { + default: break; + case AttributeList::AT_address_space: + Result = HandleAddressSpaceTypeAttribute(Result, ThisAttr); + delete ThisAttr; // Consume the attribute. + continue; + } + + LeftOverAttrs.push_back(ThisAttr); + } + + // Rechain any attributes that haven't been deleted to the DeclSpec. + AttributeList *List = 0; + for (unsigned i = 0, e = LeftOverAttrs.size(); i != e; ++i) { + LeftOverAttrs[i]->setNext(List); + List = LeftOverAttrs[i]; + } + + return List; +} + +/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the +/// specified type. +QualType Sema::HandleAddressSpaceTypeAttribute(QualType Type, + AttributeList *Attr) { + // If this type is already address space qualified, reject it. + // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers + // for two or more different address spaces." + if (Type.getAddressSpace()) { + Diag(Attr->getLoc(), diag::err_attribute_address_multiple_qualifiers); + return Type; + } + + // Check the attribute arguments. + if (Attr->getNumArgs() != 1) { + Diag(Attr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return Type; + } + Expr *ASArgExpr = static_cast(Attr->getArg(0)); + llvm::APSInt addrSpace(32); + if (!ASArgExpr->isIntegerConstantExpr(addrSpace, Context)) { + Diag(Attr->getLoc(), diag::err_attribute_address_space_not_int, + ASArgExpr->getSourceRange()); + return Type; + } + + unsigned ASIdx = static_cast(addrSpace.getZExtValue()); + return Context.getASQualType(Type, ASIdx); +} + diff --git a/clang/lib/Sema/SemaUtil.h b/clang/lib/Sema/SemaUtil.h new file mode 100644 index 00000000000..35452b18e6f --- /dev/null +++ b/clang/lib/Sema/SemaUtil.h @@ -0,0 +1,35 @@ +//===--- SemaUtil.h - Utility functions for semantic analysis -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a few static inline functions that are useful for +// performing semantic analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_UTIL_H +#define LLVM_CLANG_SEMA_UTIL_H + +#include "clang/AST/Expr.h" + +namespace clang { + +/// Utility method to determine if a CallExpr is a call to a builtin. +static inline bool isCallBuiltin(CallExpr* cexp) { + Expr* sub = cexp->getCallee()->IgnoreParenCasts(); + + if (DeclRefExpr* E = dyn_cast(sub)) + if (E->getDecl()->getIdentifier()->getBuiltinID() > 0) + return true; + + return false; +} + +} // end namespace clang + +#endif -- cgit v1.2.1